So I have in my database a table called "weeks" where I store every weeks of the years like so:
table weeks(id, year, num_week, date_min, date_max)
So for this week, the line look like this :
Note : My weeks starts on thursday and ends on Wenesday.
Since it is a pain inserting each weeks line by line, I want to create a stored procedure for this, here's what I came up with :
DELIMITER |
CREATE PROCEDURE proc_insert_weeks()
BEGIN
SELECT year, num_week, date_min, date_max INTO #year, #num_week, #date_min, #date_max
FROM weeks
ORDER BY date_min DESC LIMIT 1;
SET #date_min = DATE_ADD(#date_max INTERVAL 1 DAY);
SET #date_max = DATE_ADD(#date_min INTERVAL 6 DAY);
SET #year= YEAR(#date_min);
IF #num_week < 52 THEN SET #num_week = #num_week + 1;
ELSE SET #num_week = 1;
END IF;
INSERT INTO weeks (year, num_week, date_min, date_max)
VALUES (#year, #num_week, #date_min, #date_max);
END |
DELIMITER ;
So the idea was to take the last record of the table and add 1 week to the dates, but I can't even make it paste the creation of the procedure.
I get an error right after the SELECT query, can someone help me figure out what I am doing wrong ?
drop PROCEDURE proc_insert_weeks;
DELIMITER |
CREATE PROCEDURE proc_insert_weeks()
BEGIN
SELECT year, num_week, date_min, date_max INTO #year, #num_week, #date_min, #date_max
FROM weeks
ORDER BY date_min DESC LIMIT 1;
SET #date_min = DATE_ADD(#date_max, INTERVAL 1 DAY);
SET #date_max = DATE_ADD(#date_min, INTERVAL 6 DAY);
SET #year= YEAR(#date_min);
IF #num_week < 52 THEN SET #num_week = #num_week + 1;
ELSE SET #num_week = 1;
END IF;
INSERT INTO weeks (year, num_week, date_min, date_max)
VALUES (#year, #num_week, #date_min, #date_max);
END |
DELIMITER ;
You can try above code.
You made mistake in DATE_ADD function. You missed , in it.
I'm currently using DATE_ADD(date,INTERVAL expr type) to set a due date as a trigger in a mySQL Database.
What I'm wanting to know is if it is possible to skip weekends (Saturday, Sunday) as part of the trigger.
You'd have to create an own function for doing that. You can look how to do that in this answer, for example (just use function instead of procedure). As for how to write such a function, here's a working algorithm. The code is quite straightforward: it loops through days and skips weekends.
CREATE FUNCTION `DAYSADDNOWK`(addDate DATE, numDays INT) RETURNS date
BEGIN
IF (WEEKDAY(addDate)=5) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
IF (WEEKDAY(addDate)=6) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
WHILE numDays>0 DO
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
IF (WEEKDAY(addDate)=5) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
IF (WEEKDAY(addDate)=6) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
SET numDays=numDays-1;
END WHILE;
RETURN addDate;
END
Currently SELECT DAYSADDNOWK(CURDATE(), 5) yields 2016-03-07, which is correct.
Of course you only can use it with days, so no arbitrary interval, but your question mentioned date datatype, and I don't quite see how one could add a month not counting working days.
This function simply creates a list of dates starting at the date given in the arguments, and then figures out which date is x number of days (the interval) out while disregarding days 1 and 7 (which are Sunday and Saturday respectively on SQL Server).
CREATE FUNCTION [dbo].[udf_days_add_no_wknd]
(
#start_date date
, #interval int
)
RETURNS date
AS
BEGIN
declare #answer date
; with dates as
(
select #start_date as date_val
union all
select dateadd(d, 1, date_val) as date_val
from dates
where date_val < dateadd(d, #interval * 10, #start_date)
)
, final as
(
select top 1 lead(ld.date_val, #interval, NULL) over (order by ld.date_val asc) as new_date_val
from dates as ld
where 1=1
and datepart(dw, ld.date_val) not in (1,7) --eliminating weekends
)
select #answer = (select new_date_val from final)
return #answer
END
It is worth nothing that this solution is dependent on having SQL Server 2012 or later, considering the use of the lead() function.
I am developing a Java application using MySQL. I need to know which is the week of each month, of the stored dates. Is there any MySQL function for that ? Basically , if i was to use this for the current date (13.09) it would show me its in week number 2 and tomorrow it will be week number 3.
You can play with the WEEK() function, and see if it suits your needs. Here I'm using WEEK(date, 3) that will return the week of the year from 1 to 53, starting from Mondays:
set #my_date = '2015-09-13';
SELECT
WEEK(#my_date, 3) -
WEEK(#my_date - INTERVAL DAY(#my_date)-1 DAY, 3) + 1
AS week_number;
WEEK(date, 3) will return the week of the year of the selected date
WEEK(date - INTERVAL DAY(#my_date)-1 DAY, 3) will return the week of the year of the first day of the month of the selected date
It will return 1 for 01-March-2015 (because it's the first day of the month so it's week 1) and 2 for 02-March-2015 (because weeks starts from Mondays, so it's a new week). If this is not the desidered behaviour you should specify your requirements more precisely.
Please see a fiddle here.
Unfortunately, there isn't a "weekofmonth" function, but you could use dayofmonth, and manipulate the result a bit:
SELECT CURRENT_DATE(),
FLOOR((DAYOFMONTH(CURRENT_DATE()) - 1) / 7) + 1 AS week_of_month
Create a mysql function.
CREATE FUNCTION `WEEK_OF_MONTH`(
datee DATE
) RETURNS INT(11)
BEGIN
DECLARE DayNamee VARCHAR(20);
DECLARE StartDatee DATE;
DECLARE DayNumber INT DEFAULT 0;
SET DayNamee = (SELECT DAYNAME(datee));
SET StartDatee = (SELECT FIRST_DAY(datee));
WHILE StartDatee <= datee DO
IF DayNamee = DAYNAME(StartDatee) THEN
SET DayNumber = DayNumber + 1;
END IF;
SET StartDatee = DATE_ADD( StartDatee, INTERVAL 1 DAY);
END WHILE;
RETURN DayNumber;
END$$
DELIMITER ;
Call as --
SELECT `WEEK_OF_MONTH`('2018-12-31');
Result : 5
This is what I would like to be able to do:
SET #interval_type := MONTH;
SELECT '2012-01-01' + INTERVAL 6 #interval_type;
+------------+
|'2012-06-01'|
+------------+
And of course that doesn't work and there is no "interval" data type in MySQL.
I want to be able to store an interval value and an interval type in a table so that i can have the database quickly do the math naturally without having to write a big switch statement, ala
... ELSE IF (type = 'MONTH') { SELECT #date + INTERVAL #value MONTH; } ...
Is this supported in any way in MySQL or do you have a clever hack for this?
Thanks; you rock.
This solution may come handy to somebody implementing the job queue for cron or something similar.
Let us suppose we have a reference date (DATETIME) and interval of repetition. We would like to store both values in database and get the quick comparison whether it's already time to execute and include job into execution queue or not.
The interval could be non trivial e.g. (1 YEAR 12 DAYS 12 HOUR) and is controlled by wise user (admin) so that user is not going to use values exceeding the range of regular DATETIME data type or otherwise the conversion must be implemented first. (18 MONTH -> 1 YEAR 6 MONTH).
We can use then DATETIME data type for storing both values reference date and interval. We can define stored function using:
DELIMITER $$
CREATE DEFINER=`my_db`#`%` FUNCTION `add_interval`(`source` DATETIME, `interval` DATETIME) RETURNS datetime
BEGIN
DECLARE result DATETIME;
SET result = `source`;
SET result=DATE_ADD(result, INTERVAL EXTRACT(YEAR FROM `interval`) YEAR);
SET result=DATE_ADD(result, INTERVAL EXTRACT(MONTH FROM `interval`) MONTH);
SET result=DATE_ADD(result, INTERVAL EXTRACT(DAY FROM `interval`) DAY);
SET result=DATE_ADD(result, INTERVAL EXTRACT(HOUR FROM `interval`) HOUR);
SET result=DATE_ADD(result, INTERVAL EXTRACT(MINUTE FROM `interval`) MINUTE);
SET result=DATE_ADD(result, INTERVAL EXTRACT(SECOND FROM `interval`) SECOND);
RETURN result;
END
We can then make DATETIME arithmetic using this function e.g.
// test solution
SELECT add_interval('2014-07-24 15:58:00','0001-06-00 00:00:00');
// get job from schedule table
SELECT job FROM schedule WHERE add_interval(last_execution,repetition)<NOW();
// update date of executed job
UPDATE schedule SET last_execution=add_interval(last_execution,repetition);
You can solve this problem using prepared statements, considering there is no language construct available for use. The benefit here being you get the performance and flexibility that you want; this could easily be placed in a stored procedure or function for added value:
SET #date = '2012-01-01';
SET #value = 6;
SET #type = 'MONTH';
SET #q = 'SELECT ? + INTERVAL ? ';
SET #q = CONCAT(#s, #type);
PREPARE st FROM #q;
EXECUTE st USING #date, #value;
Alternatively, depending on your database / software architecture and the type of date/time intervals you are thinking of, you could simply this problem by using a time-scale interval:
SELECT #date + INTERVAL #value SECOND
1 second - 1
1 minute - 60
1 hour - 3600
1 day - 86400 (24 hours)
1 week - 604800 (7 days)
1 month - 2419200 (4 weeks)
Here's the simplistic approach. It works reasonably fast. You can change the order of the switch statements to optimize for speed if you feel that you will be hitting some more often then others. I have not benched this against Chris Hutchinson's solution. I ran into problems trying to wrap it into a nice function because of the dynamic SQL. Anyway, for posterity, this is guaranteed to work:
CREATE FUNCTION AddInterval( date DATETIME, interval_value INT, interval_type TEXT )
RETURNS DATETIME
DETERMINISTIC
BEGIN
DECLARE newdate DATETIME;
SET newdate = date;
IF interval_type = 'YEAR' THEN
SET newdate = date + INTERVAL interval_value YEAR;
ELSEIF interval_type = 'QUARTER' THEN
SET newdate = date + INTERVAL interval_value QUARTER;
ELSEIF interval_type = 'MONTH' THEN
SET newdate = date + INTERVAL interval_value MONTH;
ELSEIF interval_type = 'WEEK' THEN
SET newdate = date + INTERVAL interval_value WEEK;
ELSEIF interval_type = 'DAY' THEN
SET newdate = date + INTERVAL interval_value DAY;
ELSEIF interval_type = 'MINUTE' THEN
SET newdate = date + INTERVAL interval_value MINUTE;
ELSEIF interval_type = 'SECOND' THEN
SET newdate = date + INTERVAL interval_value SECOND;
END IF;
RETURN newdate;
END //
It comes with this equally simplistic benchmark test:
CREATE FUNCTION `TestInterval`( numloops INT )
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE date DATETIME;
DECLARE newdate DATETIME;
DECLARE i INT;
SET i = 0;
label1: LOOP
SET date = FROM_UNIXTIME(RAND() * 2147483647);
SET newdate = AddInterval(date,1,'YEAR');
SET i = i+1;
IF i < numloops THEN
ITERATE label1;
ELSE
LEAVE label1;
END IF;
END LOOP label1;
return i;
END //
How to calculate the difference between two dates, in the format YYYY-MM-DD hh: mm: ss and to get the result in seconds or milliseconds?
SELECT TIMEDIFF('2007-12-31 10:02:00','2007-12-30 12:01:01');
-- result: 22:00:59, the difference in HH:MM:SS format
SELECT TIMESTAMPDIFF(SECOND,'2007-12-30 12:01:01','2007-12-31 10:02:00');
-- result: 79259 the difference in seconds
So, you can use TIMESTAMPDIFF for your purpose.
If you are working with DATE columns (or can cast them as date columns), try DATEDIFF() and then multiply by 24 hours, 60 min, 60 secs (since DATEDIFF returns diff in days). From MySQL:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
for example:
mysql> SELECT DATEDIFF('2007-12-31 23:59:59','2007-12-30 00:00:00') * 24*60*60
Get the date difference in days using DATEDIFF
SELECT DATEDIFF('2010-10-08 18:23:13', '2010-09-21 21:40:36') AS days;
+------+
| days |
+------+
| 17 |
+------+
OR
Refer the below link
MySql difference between two timestamps in days?
SELECT TIMESTAMPDIFF(HOUR,NOW(),'2013-05-15 10:23:23')
calculates difference in hour.(for days--> you have to define day replacing hour
SELECT DATEDIFF('2012-2-2','2012-2-1')
SELECT TO_DAYS ('2012-2-2')-TO_DAYS('2012-2-1')
select
unix_timestamp('2007-12-30 00:00:00') -
unix_timestamp('2007-11-30 00:00:00');
If you want to add where clause with DATEDIFF then it is also possible to add where clause or condition.
Take a look of following example.
select DATEDIFF(now(), '2022-08-12 17:55:51.000000') from properties p WHERE p.property_name = 'KEY';
Result : 6
SELECT TIMESTAMPDIFF(SECOND,'2018-01-19 14:17:15','2018-01-20 14:17:15');
Second approach
SELECT ( DATEDIFF('1993-02-20','1993-02-19')*( 24*60*60) )AS 'seccond';
CURRENT_TIME() --this will return current Date
DATEDIFF('','') --this function will return DAYS and in 1 day there are 24hh 60mm 60sec
Or, you could use TIMEDIFF function
mysql> SELECT TIMEDIFF('2000:01:01 00:00:00', '2000:01:01 00:00:00.000001');
'-00:00:00.000001'
mysql> SELECT TIMEDIFF('2008-12-31 23:59:59.000001' , '2008-12-30 01:01:01.000002');
'46:58:57.999999'
This function takes the difference between two dates and shows it in a date format yyyy-mm-dd. All you need is to execute the code below and then use the function. After executing you can use it like this
SELECT datedifference(date1, date2)
FROM ....
.
.
.
.
DELIMITER $$
CREATE FUNCTION datedifference(date1 DATE, date2 DATE) RETURNS DATE
NO SQL
BEGIN
DECLARE dif DATE;
IF DATEDIFF(date1, DATE(CONCAT(YEAR(date1),'-', MONTH(date1), '-', DAY(date2)))) < 0 THEN
SET dif=DATE_FORMAT(
CONCAT(
PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))DIV 12 ,
'-',
PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))% 12 ,
'-',
DATEDIFF(date1, DATE(CONCAT(YEAR(date1),'-', MONTH(DATE_SUB(date1, INTERVAL 1 MONTH)), '-', DAY(date2))))),
'%Y-%m-%d');
ELSEIF DATEDIFF(date1, DATE(CONCAT(YEAR(date1),'-', MONTH(date1), '-', DAY(date2)))) < DAY(LAST_DAY(DATE_SUB(date1, INTERVAL 1 MONTH))) THEN
SET dif=DATE_FORMAT(
CONCAT(
PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))DIV 12 ,
'-',
PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))% 12 ,
'-',
DATEDIFF(date1, DATE(CONCAT(YEAR(date1),'-', MONTH(date1), '-', DAY(date2))))),
'%Y-%m-%d');
ELSE
SET dif=DATE_FORMAT(
CONCAT(
PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))DIV 12 ,
'-',
PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))% 12 ,
'-',
DATEDIFF(date1, DATE(CONCAT(YEAR(date1),'-', MONTH(date1), '-', DAY(date2))))),
'%Y-%m-%d');
END IF;
RETURN dif;
END $$
DELIMITER;
select TO_CHAR(TRUNC(SYSDATE)+(to_date( '31-MAY-2012 12:25', 'DD-MON-YYYY HH24:MI')
- to_date( '31-MAY-2012 10:37', 'DD-MON-YYYY HH24:MI')),
'HH24:MI:SS') from dual
-- result : 01:48:00
OK it's not quite what the OP asked, but it's what I wanted to do :-)
This code calculate difference between two dates in yyyy MM dd format.
declare #StartDate datetime
declare #EndDate datetime
declare #years int
declare #months int
declare #days int
--NOTE: date of birth must be smaller than As on date,
--else it could produce wrong results
set #StartDate = '2013-12-30' --birthdate
set #EndDate = Getdate() --current datetime
--calculate years
select #years = datediff(year,#StartDate,#EndDate)
--calculate months if it's value is negative then it
--indicates after __ months; __ years will be complete
--To resolve this, we have taken a flag #MonthOverflow...
declare #monthOverflow int
select #monthOverflow = case when datediff(month,#StartDate,#EndDate) -
( datediff(year,#StartDate,#EndDate) * 12) <0 then -1 else 1 end
--decrease year by 1 if months are Overflowed
select #Years = case when #monthOverflow < 0 then #years-1 else #years end
select #months = datediff(month,#StartDate,#EndDate) - (#years * 12)
--as we do for month overflow criteria for days and hours
--& minutes logic will followed same way
declare #LastdayOfMonth int
select #LastdayOfMonth = datepart(d,DATEADD
(s,-1,DATEADD(mm, DATEDIFF(m,0,#EndDate)+1,0)))
select #days = case when #monthOverflow<0 and
DAY(#StartDate)> DAY(#EndDate)
then #LastdayOfMonth +
(datepart(d,#EndDate) - datepart(d,#StartDate) ) - 1
else datepart(d,#EndDate) - datepart(d,#StartDate) end
select
#Months=case when #days < 0 or DAY(#StartDate)> DAY(#EndDate) then #Months-1 else #Months end
Declare #lastdayAsOnDate int;
set #lastdayAsOnDate = datepart(d,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#EndDate),0)));
Declare #lastdayBirthdate int;
set #lastdayBirthdate = datepart(d,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#StartDate)+1,0)));
if (#Days < 0)
(
select #Days = case when( #lastdayBirthdate > #lastdayAsOnDate) then
#lastdayBirthdate + #Days
else
#lastdayAsOnDate + #Days
end
)
print convert(varchar,#years) + ' year(s), ' +
convert(varchar,#months) + ' month(s), ' +
convert(varchar,#days) + ' day(s) '
If you've a date stored in text field as string you can implement this code it will fetch the list of past number of days a week, a month or a year sorting:
SELECT * FROM `table` WHERE STR_TO_DATE(mydate, '%d/%m/%Y') < CURDATE() - INTERVAL 30 DAY AND STR_TO_DATE(date, '%d/%m/%Y') > CURDATE() - INTERVAL 60 DAY
//This is for a month
SELECT * FROM `table` WHERE STR_TO_DATE(mydate, '%d/%m/%Y') < CURDATE() - INTERVAL 7 DAY AND STR_TO_DATE(date, '%d/%m/%Y') > CURDATE() - INTERVAL 14 DAY
//This is for a week
%d%m%Y is your date format
This query display the record between the days you set there like: Below from last 7 days and Above from last 14 days so it would be your last week record to be display same concept is for month or year. Whatever value you're providing in below date like: below from 7-days so the other value would be its double as 14 days. What we are saying here get all records above from last 14 days and below from last 7 days. This is a week record you can change value to 30-60 days for a month and also for a year.
Thank You Hope it will help someone.
You would simply do this:
SELECT (end_time - start_time) FROM t; -- return in Millisecond
SELECT (end_time - start_time)/1000 FROM t; -- return in Second
Why not just
Select Sum(Date1 - Date2) from table
date1 and date2 are datetime