Creating A MySQL event procedure which inserts a new record into database every day for each employee id in another table - mysql

Good Day
I have two tables named as Users and mileagesnew
The users table has an id which is unique (Primary Key) and the users.id column acts as a foreign key in the mileagesnew table.
The Users Table
The mileagesnew Table
I want to create a MySQL event to insert a new mileage record for each and every user in the Users table inside the mileagesnew table
So, the MySQL trigger i have right now is,
CREATE EVENT Daily_Mileage
ON SCHEDULE
EVERY 1 DAY
STARTS (TIMESTAMP(CURRENT_DATE) + INTERVAL 1 DAY + INTERVAL 1 HOUR)
DO
INSERT INTO `mileagesnew`(`user_id`, `date`, `mileage`, `fuel_mileage`, `fuel`, `fuel_cost`, `km`,
`kmpl`, `remarks`, `created_at`, `updated_at`) VALUES
('Need To Get The ID of every employee in users table here without
repeating',CURRENT_DATE,'0','0','0','0','0','0','0','',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP);
I am not sure how i can get the id value of each records present in the users table without having any duplicates. Is this possible or if i am doing this via mysql should i write the query individually for all users
So far the event set will run only for one user id but not for other which is set as follows,

CREATE EVENT Daily_Mileage
ON SCHEDULE
EVERY 1 DAY
STARTS (TIMESTAMP(CURRENT_DATE) + INTERVAL 1 DAY + INTERVAL 1 HOUR)
DO
INSERT INTO Mileages (user_id, `date`, mileage, fuel_mileage, fuel, fuel_cost, km, kmpl, remarks)
SELECT id, CURRENT_DATE, 0, '0', '0', '0', 0, 0, ''
FROM Users;
PS. created_at and updated_at columns are already DEFAULT CURRENT_TIMESTAMP, so they're removed. Single quotes wrapped zeros for numeric columns are removed.
PPS. TIMESTAMP function usage in STARTS is excess, STARTS CURRENT_DATE + INTERVAL '1 1' DAY_HOUR is enough.
the table name is mileagesnew not Mileage – Developer
Adjust it in the query by yourself.

Related

Select one piece of data from every day at a specific hour MySQL

My database has data imputed every 1 minute and is stored in the format 2020-04-05 16:20:04 under a column called timestamp.
I need a MySQL query to select data from every day at a specific hour (the second does not matter), for for example I want to get the data from 16:00 of every day from the past 30 days.
It currently, just grabs the data from the past 30 days and then the PHP application sorts it, however, this is causing very slow loading time, hence wanting to only select the wanted data from the database.
Example of data
Please try the following sql:
select
d.timestamp, hour(d.timestamp)
from
demo1 d
where
DATEDIFF(NOW(), d.timestamp) < 30 and hour(d.timestamp) = 16;
The create sql is as following:
CREATE TABLE `demo1` (
`id` int(11) not null auto_increment primary key,
`serverid` int(11) not null,
`timestamp` datetime not null,
KEY `idx_timestamp` (`timestamp`)
) engine = InnoDB;
insert into `demo1` (serverid, timestamp)
VALUES (1, "2020-07-05 16:20:04"),
(2, "2020-07-06 17:20:04"),
(3, "2020-07-07 16:40:04"),
(4, "2020-07-08 08:20:04"),
(5, "2020-07-05 15:20:04"),
(5, "2020-07-05 16:59:04"),
(5, "2020-06-04 16:59:04");
Zhiyong's response will work, but wont perform well. You need to figure out a way to get the query to use indexes.
You can add a simple index on timestamp and run the query this way:
SELECT
d.timestamp, d.*
FROM demo1 d
WHERE 1
AND d.timestamp > CURDATE() - INTERVAL 30 DAY
AND hour(d.timestamp) = 16;
In MySQL 5.7 and up, you can created a generated column (also called calculated column) top store the hour of the timestamp in a separate column. You can then index this column, perhaps as a composite index of hour + timestamp, so that the query above will perform really quickly.
ALTER TABLE demo1
ADD COLUMN hour1 tinyint GENERATED ALWAYS AS (HOUR(timestamp)) STORED,
ADD KEY (hour1, timestamp);
The result query would be:
SELECT
d.timestamp, d.*
FROM demo1 d
WHERE 1
AND d.timestamp > CURDATE() - INTERVAL 30 DAY
AND hour1 = 16;
More info on that here:
https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html
https://dev.mysql.com/doc/refman/5.7/en/generated-column-index-optimizations.html

create a report in mysql and store it in a log file, using triggers, and then analyze the log

I need to create a report on a monthly or daily basis (whichever is more easy) for a specific table containing the number of records that got updated, inserted or deleted in this period.
The table contains a column named updatedate and another named deleted where the value 0 means it is not deleted, and the value 1 means it was deleted. Finally, there is the primary key column, named id.
The following code returns the records deleted for a certain period of time:
SELECT * FROM orders
WHERE updateDate >='2019-01-01 00:00:00'
AND updateDate <'2019-02-13 00:00:00' AND deleted = '1'
Which queries should one run also, in order to get a report of the newly created - inserted records?
I guess one should also somehow count the number of ids that exist in the starting date, and then the number of ids that exist in the end date, and then do the subtraction in order to get the number of the newly inserted records? Ideally i would like to have these reports in separate files
CREATE TABLE orders
(
id INT PRIMARY KEY AUTO_INCREMENT,
updatedate DATETIME,
product_id INT,
deleted INT,
customer_id INT
);
INSERT INTO orders (updatedate, product_id, deleted, customer_id)
VALUES
('2019-08-15 12:20:20', '1', '0', '123'),
('2019-08-15 12:20:20', '2', '0', '123'),
('2019-08-17 16:43:09', '4', '0', '456'),
('2019-08-18 09:21:43', '8', '0', '789'),
('2019-08-18 14:23:11', '12', '0', '123'),
('2019-08-21 08:34:21', '19', '0', '456');
example output of the updated records: (assuming the record ids are not new for the month under question)
date total_updates
2009-08-15 2
2009-08-17 1
2009-08-18 2
2009-08-21 1
Same table is needed for the records deleted and created in a month basis. This must be based only on the record ids that differ from the previous month.
ie if id 88 was not in the table orders in the last day of the previous month, then this is a newly inserted record. If id 13 was in the table orders in the last previous month's last day, and in this month's last day it is not, then this is a deleted record (something which may also occur from the column deleted combined with the updatedate column)
So this report could look like:
January:
123 records inserted
456 records deleted
EDIT: as was kindly spotted, in the comments, this approach is not totally safe, since we may loose some actions. Could you please elaborate on the solution
"A safer approach is to capture all events to a log using triggers and analyse that" given the fact that any change to the current scheme is not allowed, but we can store data in a new external scheme.

SQL - insert new row depends on previous data from same table

I have a table with Car name. Here is a pseudo-table :
This table has been fallen with data like :
order = 14214
type = 0
created = 2017-12-10 23:39:23
I want to some operation with this data :
1 - find data till 6 days ago.
2 - (For each records of step 1)
I want to insert new record with order same as step1.order and with type= 1.
For first step , I found out I use
select *
from cars
WHERe `created` <= Date(Now()) - INTERVAL 6 day
but for next step, Is there any suggestion?
EDITED: :
Ex . I had a table with 250 records, after inserting new data, my table would be 500 rows with A table and A' (B&B',...) for each order.
You can try as below script.
Note: I assume ID field is auto-increment primary key.
insert into cars (`order`, type, created)
select `order`, 1 type, created
from cars
WHERe `created` <= Date(Now()) - INTERVAL 6 day
Hope it can help.

MySQL event variables - copy value to another table

DELIMITER |
CREATE EVENT myevent
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 MINUTE
DO
BEGIN
DELETE FROM vehicle WHERE last_updated < (NOW() - INTERVAL 5 MINUTE)
END |
DELIMITER ;
Above I have a MySQL event that runs every minute deleting rows that haven't been updated for 5 minutes. I have another table called saved_vehicles. All of the rows in vehicle will have a row in the saved_vehicle table. What I want to do is essentially copy over the last_updated time to the saved_vehicle table (for example purposes, imagine the saved_vehicle field would be last_known_online_time. This essentially saves a copy of the vehicle with its last known online time.
Essentially I'm creating a backup before deleting the row.
Insert into saved_vehicles before delete.
Try this:
DELIMITER |
CREATE EVENT myevent
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 MINUTE
DO
BEGIN
SET #time = NOW() - INTERVAL 5 MINUTE;
# select * is not very smart, it will also copy your primary key,
# so you can get error about duplicates. Listing fields would work here.
INSERT INTO saved_vehicle (SELECT * FROM vehicle WHERE last_updated < #time);
DELETE FROM vehicle WHERE last_updated < #time;
END |
DELIMITER ;
To avoid listing fields i've mentioned in comment try to select all fields except your primary key column.
To do this check how to select all columns except one
update
I through about insert i mentioned above - and if your saved_vehicle table has same structure as vehicle table, but its primary key has different name than vehicle (f.e. base_id, when vehicle PK is id) and its int auto_increment then it will work nice as it is.

SQL query that returns all dates not used in a table

So lets say I have some records that look like:
2011-01-01 Cat
2011-01-02 Dog
2011-01-04 Horse
2011-01-06 Lion
How can I construct a query that will return 2011-01-03 and 2011-01-05, ie the unused dates. I postdate blogs into the future and I want a query that will show me the days I don't have anything posted yet. It would look from the current date to 2 weeks into the future.
Update:
I am not too excited about building a permanent table of dates. After thinking about it though it seems like the solution might be to make a small stored procedure that creates a temp table. Something like:
CREATE PROCEDURE MISSING_DATES()
BEGIN
CREATE TABLE TEMPORARY DATES (FUTURE DATETIME NULL)
INSERT INTO DATES (FUTURE) VALUES (CURDATE())
INSERT INTO DATES (FUTURE) VALUES (ADDDATE(CURDATE(), INTERVAL 1 DAY))
...
INSERT INTO DATES (FUTURE) VALUES (ADDDATE(CURDATE(), INTERVAL 14 DAY))
SELECT FUTURE FROM DATES WHERE FUTURE NOT IN (SELECT POSTDATE FROM POSTS)
DROP TABLE TEMPORARY DATES
END
I guess it just isn't possible to select the absence of data.
You're right — SQL does not make it easy to identify missing data. The usual technique is to join your sequence (with gaps) against a complete sequence, and select those elements in the latter sequence without a corresponding partner in your data.
So, #BenHoffstein's suggestion to maintain a permanent date table is a good one.
Short of that, you can dynamically create that date range with an integers table. Assuming the integers table has a column i with numbers at least 0 – 13, and that your table has its date column named datestamp:
SELECT candidate_date AS missing
FROM (SELECT CURRENT_DATE + INTERVAL i DAY AS candidate_date
FROM integers
WHERE i < 14) AS next_two_weeks
LEFT JOIN my_table ON candidate_date = datestamp
WHERE datestamp is NULL;
One solution would be to create a separate table with one column to hold all dates from now until eternity (or whenever you expect to stop blogging). For example:
CREATE TABLE Dates (dt DATE);
INSERT INTO Dates VALUES ('2011-01-01');
INSERT INTO Dates VALUES ('2011-01-02');
...etc...
INSERT INTO Dates VALUES ('2099-12-31');
Once this reference table is set up, you can simply outer join to determine the unused dates like so:
SELECT d.dt
FROM Dates d LEFT JOIN Blogs b ON d.dt = b.dt
WHERE b.dt IS NULL
If you want to limit the search to two weeks in the future, you could add this to the WHERE clause:
AND d.dt BETWEEN NOW() AND ADDDATE(NOW(), INTERVAL 14 DAY)
The way to extract rows from the mysql database is via SELECT. Thus you cannot select rows that do not exist.
What I would do is fill my blog table with all possible dates (for a year, then repeat the process)
create table blog (
thedate date not null,
thetext text null,
primary key (thedate));
doing a loop to create all dates entries for 2011 (using a program, eg $mydate is the date you want to insert)
insert IGNORE into blog (thedate,thetext) values ($mydate, null);
(the IGNORE keyword to not create an error (thedate is a primary key) if thedate exists already).
Then you insert the values normally
insert into blog (thedate,thetext) values ($mydate, "newtext")
on duplicate key update thetext="newtext";
Finally to select empty entries, you just have to
select thedate from blog where thetext is null;
You probably not going to like this:
select '2011-01-03', count(*) from TABLE where postdate='2011-01-03'
having count(*)=0 union
select '2011-01-04', count(*) from TABLE where postdate='2011-01-04'
having count(*)=0 union
select '2011-01-05', count(*) from TABLE where postdate='2011-01-05'
having count(*)=0 union
... repeat for 2 weeks
OR
create a table with all days in 2011, then do a left join, like
select a.days_2011
from all_days_2011
left join TABLE on a.days_2011=TABLE.postdate
where a.days_2011 between date(now()) and date(date_add(now(), interval 2 week))
and TABLE.postdate is null;