I am writing an event scheduler in Mysql for generating tickets 3 hour prior to the user travel time. Mysl is installed in server where the server time is in UTC and 12 hour format with 5:30 hour difference with IST time. I have one user whose travel time is 7:30 in the morning, so i need to generate ticket for this user at 4:30 in the morning. I am getting current server time and converting to IST and comparing travel time and current converted time difference is 3 hours. But some how its failing and always ticket creating at 10 am in the morning. Below is my complete event writtent in Mysql,
DELIMITER $$
ALTER EVENT `Auto_Generated_Ticket` ON SCHEDULE EVERY 1 MINUTE STARTS CURRENT_TIMESTAMP ON COMPLETION PRESERVE ENABLE DO BEGIN
DECLARE UserId INT;
DECLARE v_finished INT DEFAULT 0;
DECLARE GetDate DATE DEFAULT DATE(NOW());
/*get all active user's who's tariff enddate is > today and available journeys > 0 and pass-status=4(delivered)*/
DECLARE ActiveUserId CURSOR FOR
SELECT UT.user_id FROM `um.user_trs.tariff` UT
INNER JOIN `um.user` U ON U.user_id=UT.user_id
INNER JOIN `um.user_ps.pass` UP ON UP.user_id=UT.user_id
INNER JOIN `ps.pass` P ON P.pass_id=UP.pass_id
WHERE UT.end_date >=DATE(NOW()) AND UT.available_journeys > 0 AND UT.current_balance>0 AND P.status_id=4
GROUP BY UT.user_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished=1;
SET #GetTime= DATE_FORMAT(NOW(),'%Y-%m-%d %h:%i:%s %p');
OPEN ActiveUserId;
get_userid:LOOP
FETCH ActiveUserId INTO UserId;
IF v_finished=1 THEN
LEAVE get_userid;
END IF;
SET #StartTime=(SELECT RS.start_time FROM `um.user_rm.route` UR
INNER JOIN `rm.route_schedule` RS ON RS.route_schedule_id=UR.route_schedule_id
WHERE UR.user_id=UserId
ORDER BY ABS( TIMEDIFF( RS.`start_time`, TIME(CONVERT_TZ(#GetTime,'+00:00','+05:30')) ) ) LIMIT 1);
SET #TimeDiff=(HOUR(TIMEDIFF(#StartTime,TIME(CONVERT_TZ(#GetTime,'+00:00','+05:30')))));
/*if time difference between current time and schedule start time is 3 hours then generate ticket for the user for that particular schedule*/
IF (#TimeDiff =3) THEN
/*IF (#TNumber IS NULL) THEN*/
IF NOT EXISTS(SELECT ticket_number FROM `um.user_ts.ticket` WHERE route_id=#RouteId AND route_schedule_id=#RoutScheduleId
AND user_id=UserId AND DATE(date_of_issue)=#ISTDATE) THEN
INSERT INTO `um.user_ts.ticket`
(
`user_id`,`route_id`,`route_schedule_id`,`ticket_number`,`date_of_issue`,`is_cancelled`,
`amount_charged`,`user_tariff_id`,`opening_balance`,`is_auto_generated`
)
VALUES
(
UserId,#RouteId,#RoutScheduleId,#TicketNumber,CONVERT_TZ(UTC_TIMESTAMP(),'+00:00','+05:30'),
FALSE,#PerJourneyCost,#UserTariffId,#TariffCurrentBalance,1
);
END IF;/*end of route and schedule check*/
END IF; /*end of time difference check*/
END LOOP get_userid;
CLOSE ActiveUserId;
END$$
DELIMITER ;
Please let me know if any other way to convert time or any mistake which i am not noticing in the above query.
Regards
Sangeetha
There is a dedicated mysql command to do so. CONVERT_TZ(dt,from_tz,to_tz)
See here https://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_convert-tz
From their docs:
CONVERT_TZ() converts a datetime value dt from the time zone given by
from_tz to the time zone given by to_tz and returns the resulting
value
Maybe the warning applies to you ?
Warning
Do not use a downloadable package if your system has a zoneinfo
database. Use the mysql_tzinfo_to_sql utility instead. Otherwise, you
may cause a difference in datetime handling between MySQL and other
applications on your system.
I would break it down to a minimalistic example and see if this works.
Here's how I would do it to test the basics:
Simple example:
SELECT CONVERT_TZ('2016-05-24 12:00:00','GMT','MET');
So you could build a query to determine the timediff like this:
HOUR(TIMEDIFF(
CONVERT_TZ('2016-05-24 12:00:00','GMT','MET'),
'2016-05-24 12:00:00'
))
Related
Hi my problem relates to adding days onto a date from two different tables in MySql in the Mamp environment.
Membership type to Membership transaction is 1 to many
The link is type_id
Date is in yyyy/mm/dd format also as this is the only format that Mamp will allow from my research.
I want a new end date column that links to the column duration from the membership type table. I want to add Duration_day onto start_date to produce an end date that matches up with the type_id. (So they link up to give the correct end date)
I want it to be automatically calculated when the start date and type-id are saved
Any help would be appreciated
Thanks
You will need a trigger on INSERT/UPDATE - a calculated column (for MySQL v5.7.6+) will not work in your case (it can only refer to columns in the same table).
The 2 triggers may look like this
CREATE DEFINER = 'root'#'%' TRIGGER `m_duration_ins_tr1` BEFORE INSERT ON `membership`
FOR EACH ROW
BEGIN
DECLARE duration INTEGER;
SELECT m_duration INTO duration FROM membership_type WHERE id = NEW.type_id;
SET NEW.end_date := DATE_ADD(NEW.start_date, INTERVAL duration DAY);
END;
CREATE DEFINER = 'root'#'%' TRIGGER `m_duration_ins_tr1` BEFORE UPDATE ON `membership`
FOR EACH ROW
BEGIN
DECLARE duration INTEGER;
SELECT m_duration INTO duration FROM membership_type WHERE id = NEW.type_id;
SET NEW.end_date := DATE_ADD(NEW.start_date, INTERVAL duration DAY);
END;
I have a problem for which a 15 minute search on SO couldn't get an answer. I have a database with a table called bugs, which is used to store some info about bugs in a system we are developing. Columns of importance are open_date, close_date and status of severity of the bug introduced. I need to make an SQL statement to display counted number of opened bugs for each of dates from a range of dates which is entered. A bug is considered open on “2012-01-01” if it is created on or
before “2012-01-01” (i.e. the same day) and closed on or after “2012-01-02” (i.e. day after that date).
I have made an sql for finding unit functionality of the requirement:
SELECT COUNT(DATE(Open_Date)) BugsOpen
, DATE(Open_Date) Dated
FROM bugs
WHERE DATE(open_date) <= (STR_TO_DATE('21/10/17','%d/%m/%Y'))
AND DATE(close_date) >= (DATE_ADD(STR_TO_DATE('21/10/17','%d/%m/%Y'),INTERVAL 1 DAY))
OR close_date IS NULL);
Which is working but I need this in like a function call or stored procedure call, ex. showBugs('21/10/17 - 29/10/17'), to display for each of the dates in the range input in this function/procedure.
I have found a way to extract to and from dates.
SELECT SUBSTRING('21/10/17 - 29/10/17', -19, 8) as from_date,
SUBSTRING('21/10/17 - 29/10/17' FROM 12) as to_date;
But I am really having trouble writing a simple procedure. I have started writing some code:
DROP PROCEDURE IF EXISTS showBugs;
CREATE DEFINER = 'root'#'localhost' PROCEDURE showBugs(rangeOfDates TEXT)
BEGIN
SET #from_date = SUBSTRING(rangeOfDates, -19, 8);
SET #to_date = SUBSTRING(rangeOfDates FROM 12);
REPEAT SET #from_date
END REPEAT;
END;
call showBugs('21/10/17 - 29/10/17');
I am really in a rut here and would be grateful if someone is to help me either with stored procedure or function implementation.
I have a MySQL database with one big table in it. After a while, it becomes too full and performance degrades. Every Sunday, I want to delete rows whose last update is older than a certain number of days ago.
How do I do that?
Make a Scheduled Event to run your query every night. Check out Event Scheduler as well.
CREATE EVENT `purge_table` ON SCHEDULE
EVERY 1 DAY
ON COMPLETION NOT PRESERVE
ENABLE
COMMENT ''
DO BEGIN
DELETE FROM my_table WHERE my_timestamp_field <= now() - INTERVAL 5 DAY
END
What is the table design? Do you have a column with a timestamp?
Assuming you do, you could use that timestamp value with a datediff(your_date,CURDATE()) in a delete command.
Delete from table where datediff(date_col, CURDATE ()) > your_num_days.
Self Answer
Make a web server that sends the following SQL to the database every weekend:
DELETE FROM table WHERE timestamp < DATE_SUB(NOW(), INTERVAL 7 DAY);
or
DELETE FROM table
WHERE timestamp < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 7 DAY))
I might need locking to prevent accumulation of jobs, like so:
DELIMITER //
CREATE EVENT testlock_event ON SCHEDULE EVERY 2 SECOND DO
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
DO RELEASE_LOCK('testlock_event');
END;
IF GET_LOCK('testlock_event', 0) THEN
-- add some business logic here, for example:
-- insert into test.testlock_event values(NULL, NOW());
END IF;
DO RELEASE_LOCK('testlock_event');
END;
//
DELIMITER ;
Final answer:
CREATE EVENT `purge_table` ON SCHEDULE
EVERY 1 DAY
ON COMPLETION NOT PRESERVE
ENABLE
COMMENT ''
DO BEGIN
IF GET_LOCK('purge_table', 0) THEN
DELETE FROM table WHERE timestamp < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 7 DAY));
END;
Maybe you can provide more information on how you are pushing the data to the DB and how you are working on the DB in general? Therefore we can help you and don't have to struggle with the dark...
I'll provide an easy solution: It's kind of workaround, but works:
Everytime you touch the data you update a time stamp in the updated rows.
Therefore you could easily filter them out every sunday.
UPDATE
The answer, the author provided by himself, was discussed at Stackoverflow and seems not to work in exactly that way, compare the discussion.
I am using SAILS JS and mysql adapter is being used. I have a model named as User with the following fields ID, USERNAME, EMAIL, ACTIVE_STATUS and CREATED_DATE.
By Default, active_status is set as 0. I want to update the status is 1 when created_date + 3 days is equal on Today.
Kindly suggest any possible ways to do this.
Hope you can use MySQL’s Event Scheduler
Activate it by: SET GLOBAL event_scheduler = ON;
Create event syntax:
CREATE EVENT `event_name`
ON SCHEDULE schedule
[ON COMPLETION [NOT] PRESERVE]
[ENABLE | DISABLE | DISABLE ON SLAVE]
DO BEGIN
-- event body
END;
The schedule can be assigned various settings, e.g.
Run once on a specific date/time:
AT ‘YYYY-MM-DD HH:MM.SS’
e.g. AT ‘2011-06-01 02:00.00’
Run once after a specific period has elapsed:
AT CURRENT_TIMESTAMP + INTERVAL n [HOUR|MONTH|WEEK|DAY|MINUTE]
e.g. AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
Run at specific intervals forever:
EVERY n [HOUR|MONTH|WEEK|DAY|MINUTE]
e.g. EVERY 1 DAY
Run at specific intervals during a specific period:
EVERY n [HOUR|MONTH|WEEK|DAY|MINUTE] STARTS date ENDS date
e.g. EVERY 1 DAY STARTS CURRENT_TIMESTAMP + INTERVAL 1 WEEK ENDS ‘2012-01-01 00:00.00’
Example:
SET GLOBAL event_scheduler = ON; -- enable event scheduler.
SELECT ##event_scheduler; -- check whether event scheduler is ON/OFF
CREATE EVENT e_store_ts -- create your event
ON SCHEDULE
EVERY 24 HOURS -- run every 24 hours
DO
UPDATE myschema.users set active_status = 1
Refer: http://dev.mysql.com/doc/refman/5.5/en/create-event.html
I have created a new column called DesiredTimeOfFileCreation of type time(7); this will indicate at what time the data is to be extracted to an export file.
Let's suppose it is set to 6:00:00. I then have a SQL agent job scheduled at 6:00 (probably every 30 minutes), but it might run at 6:00:05 or even 6:01. I want to select all rows where the DesiredTimeOfFileCreation is less than 30 minutes ago.
Does someone already have a user-defined TimeDiff function? Or is there an easy alternative that I'm missing?
As Martin mentioned above, I need to handle the midnight wrap-around.
This seems overly complicated. The code below seems to work if one time is one hour before midnight, and one is within an hour after. Would be nice to make it more generic. I think the only way to do that would be to make up a dummy date, which I may experiment with next.
The reason I'm passing a date in the unit test is that I will be passing a casted version of GetUTCDate() as a parm:
ALTER FUNCTION TimeDiffMinutes
(
#FirstTime time(7),
#SecondTime time(7)
)
RETURNS int
AS
BEGIN
/*
Unit Test:
select dbo.TimeDiffMinutes('13:31',cast ('2013-06-10 13:35' as time)), -- simple test
dbo.TimeDiffMinutes('23:55',cast ('2013-06-10 00:05' as time)) -- test midnight wrap-around
select dbo.TimeDiffMinutes('23:55',cast ('2013-06-10 00:05' as time)) -- test midnight wrap-around
*/
-- Declare the return variable here
DECLARE #resultMinutes int
DECLARE #Hour int
-- although we can compare two times, the problem is that if one time is 11:55 and the other is 00:05, we want to show 10 minutes difference.
-- We cannot add 24 hours to a time, because that would be an invalid value
Set #Hour = datePart(hour,#SecondTime)
if (#Hour <= 0)
begin
-- increase both times by an hour so we can compare them, 23:55 will wrap around to 01:55
Set #FirstTime = DateAdd(hour,+1,#FirstTime)
Set #SecondTime = DateAdd(hour,+1,#SecondTime)
end
SET #resultMinutes = DATEDIFF(Minute,#FirstTime,#SecondTime)
-- Return the result of the function
RETURN #resultMinutes
END
NOTE: This code shows that you cannot go past 24 hours in a time; it just wraps back around (with no error!):
declare #FirstTime time(7)
SET #FirstTime = '23:05'
print #FirstTime
Set #FirstTime = DATEADD(HOUR,1,#FirstTime)
print #FirstTime
Improved version, using an arbitrary date.
ALTER FUNCTION TimeDiffMinutes
(
#FirstTime time(7),
#SecondTime time(7)
)
RETURNS int
AS
BEGIN
/*
Unit Test:
select dbo.TimeDiffMinutes('13:31',cast ('2013-06-10 13:35' as time)), -- simple test
dbo.TimeDiffMinutes('23:55',cast ('2013-06-10 00:05' as time)) -- test midnight wrap-around
select dbo.TimeDiffMinutes('23:55',cast ('2013-06-10 00:05' as time)) -- test midnight wrap-around
*/
-- Declare the return variable here
DECLARE #resultMinutes int
DECLARE #Hour int
DECLARE #FirstDate datetime
DECLARE #SecondDate datetime
Set #FirstDate = CAST('2001-01-01 ' + Convert(varchar(12),#FirstTime) as DateTime)
Set #SecondDate = CAST('2001-01-01 ' + Convert(varchar(12),#SecondTime) as DateTime)
-- although we can compare two times, the problem is that if one time is 11:55 and the other is 00:05, we want to show 10 minutes difference.
-- We cannot add 24 hours to a time, because that would be an invalid value
Set #Hour = datePart(hour,#SecondDate)
if (#Hour <= 0)
begin
-- increase both times by an hour so we can compare them, 23:55 will wrap around to 01:55
Set #SecondDate = DateAdd(day,+1,#SecondDate)
end
SET #resultMinutes = DATEDIFF(Minute,#FirstDate,#SecondDate)
-- Return the result of the function
RETURN #resultMinutes
END
This is how I will use the function. We store the local time that an airport wants an extract file in a table. Then we will use SQL agent or BizTalk to poll every 30 minutes looking for work to do. AirportCode is a column in the table, and we have our own crazy function that converts for timezones.
select *,
dbo.TimeDiffMinutes(
DesiredFileCreationTimeLocal,
cast(dbo.LocationLocalTimeFromAirportCode(AirportCode,GETUTCDATE()) as time)
) as 'MinutesAgo'
from TransactionExtractDistribution
where dbo.TimeDiffMinutes(
DesiredFileCreationTimeLocal,
cast(dbo.LocationLocalTimeFromAirportCode(AirportCode,GETUTCDATE()) AS time)
) < 30
This will probably work for me:
WHERE DATEDIFF(Minute,DesiredFileCreationTimeLocal,cast(GETDATE() as time)) < 30
I had to research what happened if you pass a Time as a variable to the DateDiff function.
It seems to work, the only trick is then how to pass two times to it.
My real-world scenario is more complex, because we are dealing with different locations in different time zones, so there will some UTC conversions added to the above.