Mysql/Doctrine - Check if month is between 2 dates - mysql

I have a table let's say road_trip with a startDate and endDate columns.
I would like to make a query that can search if a month or multiple months (gonna be an array) lies between startDate and endDate.
For exemple if startDate = "2020-05-21" and endDate = "2025-05-22"
For given month = 5 (corresponding to May), we should have some result.
But for this exemple: startDate = "2020-06-21" and endDate = "2020-07-22"
For given month = 5 (corresponding to May), we should not have any result since month don't lie between date.
I don't know how to write my efficient query.
I started with the native function MONTH but it doesn't work properly since i need to check the year if for example the year of startDate is 2020 and for endDate we have 2025. The month will automatically between them but if years are the same, it may not lie between the dates.
Thank you all

This works under MySQL 8 and Mariadb 10.3 and will not be fast
CREATe TABLE road_trip (startDate Date,endDate Date)
INSERT INTO road_trip VALUES("2020-06-21", "2020-07-22" ),("2020-04-21", "2020-07-22" )
create fUNCTION findnemo( _startdate date ,_enddate date, _amonth int)
RETURNS INT
DETERMINISTIC
BEGIN
WITH RECURSIVE t as (
select _startdate as dt
UNION
SELECT DATE_ADD(t.dt, INTERVAL 1 DAY) FROM t WHERE DATE_ADD(t.dt, INTERVAL 1 DAY) <= _enddate
)
select SUM(MONTH(dt) = _amonth) into #count FROM t;
RETURN #count > 0;
END
✓
SELECT * FROM road_trip WHERE findnemo(startDate,endDate,5) > 0
startDate | endDate
:--------- | :---------
2020-04-21 | 2020-07-22
db<>fiddle here

Related

Count Number of a Specific Day(s) Between Two Dates

I have a single line in MySQL table: volunteers
user_id | start_date | end_date
11122 | 2017-04-20 | 2018-02-17
How can I find how many times the 3rd day or 24th day of a month appears? (i.e. 2017-05-03, 2017-06-03, 2017-12-24, 2018-01-24) I'm trying to get to the following count:
Sample Output:
user_id | number_of_third_day | number_of_twenty_fourth_day
11122 | 10 | 10
I look at the documentation online to see if there is a way I can say (pseudo):
SELECT
day, COUNT(*)
FROM volunteers
WHERE day(between(start_date, end_date)) in (3,24)
I tried to create a calendar table to no avail, but I would try to get the days, GROUP BY day, and COUNT(*) times that day appears in the range
WITH calendar AS (
SELECT start_date AS date
FROM volunteers
UNION ALL
SELECT DATE_ADD(start_date, INTERVAL 1 DAY) as date
FROM volunteers
WHERE DATE_ADD(start_date, INTERVAL 1 DAY) <= end_date
)
SELECT date FROM calendar;
Thanks for any help!
This one is more optimized since I generate date range by months not days as other questions, so its faster
WITH RECURSIVE cte AS
(
SELECT user_id, DATE_FORMAT(start_date, '%Y-%m-03') as third_day,
DATE_FORMAT(start_date, '%Y-%m-24') as twenty_fourth_day,
start_date, end_date
FROM table1
UNION ALL
SELECT user_id,
DATE_FORMAT(third_day + INTERVAL 1 MONTH, '%Y-%m-03') as third_day,
DATE_FORMAT(twenty_fourth_day + INTERVAL 1 MONTH, '%Y-%m-24') as twenty_fourth_day,
start_date, end_date
FROM cte
WHERE third_day + INTERVAL 1 MONTH <= end_date
)
SELECT user_id,
SUM(CASE WHEN third_day BETWEEN start_date AND end_date THEN 1 ELSE 0 END) AS number_of_third_day,
SUM(CASE WHEN twenty_fourth_day BETWEEN start_date AND end_date THEN 1 ELSE 0 END) AS number_of_twenty_fourth_day
FROM cte
GROUP BY user_id;
Demo here
A dynamic approach is.
but creating the dateranges, takes a lot of time, so you should have a date table to get the dates
CREATE TABLE table1
(`user_id` int, `start_date` varchar(10), `end_date` varchar(10))
;
INSERT INTO table1
(`user_id`, `start_date`, `end_date`)
VALUES
(11122, '2017-04-20', '2018-02-17')
,(11123, '2019-04-20', '2020-02-17')
;
Records: 2 Duplicates: 0 Warnings: 0
WITH RECURSIVE cte AS (
SELECT
user_id,
`start_date` as date_run ,
`end_date`
FROM table1
UNION ALL
SELECT
user_id,
DATE_ADD(cte.date_run, INTERVAL 1 DAY),
end_date
FROM cte
WHERE DATE_ADD(date_run, INTERVAL 1 DAY) <= end_date
)SELECT user_id,
SUM(DAYOFMONTH(date_run) = 3) as day_3th,
SUM(DAYOFMONTH(date_run) = 24) as day_24th
FROM cte
GROUP BY user_id
user_id
day_3th
day_24th
11122
10
10
11123
10
10
fiddle
In last MySQL version you can use recursion:
-- get list of all dates in interval
with recursive dates(d) as (
select '2017-04-20'
union all
select date_add(d, interval 1 day) from dates where d < '2018-02-17'
) select
-- calculate
sum(day(d) = 10) days_10,
sum(day(d) = 24) days_24
from dates
-- filter 10 & 24 days
where day(d) = 10 or day(d) = 24;
https://sqlize.online/sql/mysql80/c00eb7de69d011a85502fa538d64d22c/
As long as you are looking for days that occur in every month (so not the 29th or beyond), this is just straightforward math. The number of whole calendar months between two dates (exclusive) is:
timestampdiff(month,start_date,end_date) - (day(start_date) <= day(end_date))
Then add one if the start month includes the target day and one if the end month includes it:
timestampdiff(month,start_date,end_date) - (day(start_date) <= day(end_date))
+ (day(start_date) <= 3) + (day(end_date) >= 3)

MySQL: Find birthdays between a date range, but ignoring the year

I'm trying to query for users with birthdays falling between a given date range.
The users table stores birthdays in a pair of int columns: dob_month (1 to 12) and dob_day (1 to 31). The date range I'm querying with is a pair of date-time strings, including the year.
Here's what I've got so far:
SELECT *
FROM `users`
WHERE DATE(CONCAT_WS('-', 2023, dob_month, dob_day)) BETWEEN '2023-03-01 00:00:00' AND '2023-03-31 23:59:59'
However, this doesn't work when the date range spans multiple years.
For example, 2023-12-15 00:00:00 and 2024-01-10 23:59:59.
How can I work around this? Thanks!
You can solve this by joining to a set of rows with individual dates.
Suppose you had another table called dates which had one row per day, spanning the whole range you need.
mysql> create table dates (date date primary key);
mysql> insert into dates(date)
with recursive cte as (
select '2023-01-01' as date
union
select cte.date + interval 1 day from cte where cte.date < '2025-01-01'
)
select * from cte;
Query OK, 732 rows affected (0.01 sec)
Now it's easy to query a subset of dates:
mysql> SELECT date
FROM dates
WHERE dates.date BETWEEN '2023-12-15 00:00:00' AND '2024-01-10 23:59:59';
...
27 rows in set (0.00 sec)
We create a sample user with a dob of January 3.
mysql> create table users ( id serial primary key, dob_month tinyint, dob_day tinyint);
mysql> insert into users set dob_month = 1, dob_day = 3;
You can join your users table to that subset of dates where the month and day match.
mysql> SELECT date FROM users JOIN dates
ON dob_month = MONTH(date) AND dob_day = DAY(date)
WHERE dates.date BETWEEN '2023-12-15 00:00:00' AND '2024-01-10 23:59:59';
+------------+
| date |
+------------+
| 2024-01-03 |
+------------+
In the below code, the logic is to convert dob_month and dob_day into a date and then do the comparison using BETWEEN operator.
Now the year value used for date conversion is based on the below logic :
Use the year value the same as that of "from date". If the date is less than the "from date", then push it to the next year. Use BETWEEN operator to check if the date is within the given date range. This logic is applied because to use BETWEEN operator the date has to be greater than or equal to the "from date" keeping month and day values intact.
Note Date_add(Date_add(Makedate(some_year_value, 1), INTERVAL (dob_month)-1 month), INTERVAL (dob_day)-1 day) is repeated 3 times. It is for creating a date out of the year, month, and day values.
SET #fromdate = date('2023-09-01 00:00:00');
SET #fromyear = year(#fromdate);
SET #todate = date('2024-02-28 23:59:59');
CREATE TABLE users
(
id SERIAL PRIMARY KEY,
dob_month TINYINT,
dob_day TINYINT
);
INSERT INTO users
SET dob_month = 2,
dob_day = 1;
SELECT *
FROM users
WHERE CASE
WHEN Date_add(Date_add(Makedate(#fromyear, 1),
INTERVAL (dob_month)-1 month),
INTERVAL (dob_day)-1 day) < #fromdate THEN
Date_add(Date_add(Makedate(#fromyear + 1, 1),
INTERVAL (dob_month)-1 month),
INTERVAL (dob_day)-1 day) BETWEEN #fromdate AND #todate
ELSE Date_add(Date_add(Makedate(#fromyear, 1),
INTERVAL (dob_month)-1 month),
INTERVAL (dob_day)-1 day) BETWEEN #fromdate AND #todate
end;
Psuedo code for understanding the crux:
SELECT *
FROM users
WHERE CASE
WHEN Date(from_date_year,dob_month,dob_day) < #fromdate THEN
Date(from_date_year,dob_month,dob_day) BETWEEN #fromdate AND #todate
ELSE Date(from_date_year + 1,dob_month,dob_day) BETWEEN #fromdate AND #todate
end;

MySql: Create datetime from year and month

I have the following query:
SELECT count(*) as 'count'
FROM myTable
WHERE myDateTime >= DATE1 AND myDateTime < DATE2
-myDateTime is of type datetime (2013-01-30 08:48:13) in myTable.
-DATE1 and DATE2 should be created as datetime also so I could compare them, like this:
-DATE1 should to be created from year (eg 2013) and month (eg 01) parameters, and the day should always be 01 (the first day of the month)
-DATE2 should be same as DATE1 with an added month. (if DATE1 is 2013-01-01 00:00:00 then DATE2 should be 2013-02-01 00:00:00)
You can create the date as a number and then convert it to a date:
where myDateTime >= date(#year * 10000 + #month * 100 + 1) and
myDateTime < date_add(date(#year * 10000 + #month * 100 + 1), interval 1 month)

Finding month difference and then remaining days after months - mysql

I need to find the difference between two dates to do some calculations based on the result.
Let's say column start_date is having value 1/Jan/2014 and column and end_date is having value 15/Mar/2014. The result I want is following format:
months | days_remain |
----------------------
2 15
I can find MONTH difference and also DAY difference between separately (as 2 Months & 74 days) using TIMESTAMPDIFF function. But how to find out the remaining 15 days ?
You can use DATEDIFF to see the difference between 2 dates
SELECT DATEDIFF('2006-04-01','2005-04-01');
http://lists.mysql.com/mysql/196414
Try This, I hope it will Work For You.
select DateDiff(d, datepart(month,[Start_Date]),datepart(month,End_Date)) as Months,
(30-day(end_date)) as Days_remain
from Sdate
This will work for sure.
Declare #StartDate datetime
Declare #EndDate datetime
Declare #years varchar(40)
Declare #months varchar(30)
Declare #days varchar(30)
set #StartDate ='2014/01/01'
set #EndDate = '2014/03/15'
select #years=datediff(year,#StartDate,#EndDate)
select #months=datediff(month,#StartDate,#EndDate)-(datediff(year,#StartDate,#EndDate)*12)
select #days=datepart(d,#EndDate)-datepart(d,#StartDate)
select #years +' years, ' +#months +' months, '+#days +' days' asYearMonthDay
I think this might be what you want. It does however return 14 days for remaining, but as Jaugar Chang pointed out in a comment that should be correct if as the difference between March 1st and March 15th is 14 days.
select
timestampdiff(
month,
start_date,
end_date
) as months,
datediff(
end_date,
timestampadd(
month,
timestampdiff(
month,
start_date,
end_date
)
,start_date
)
) as days_remain
from test;
Sample SQL Fiddle
Sample result:
| START_DATE | END_DATE | MONTHS | DAYS_REMAIN |
|------------------|----------------|--------|-------------|
| January, 01 2014 | March, 15 2014 | 2 | 14 |
| January, 10 2014 | March, 13 2014 | 2 | 3 |
Try this. See the sample data as well:
select
dt1, dt2,
trunc( months_between(dt2,dt1) ) mths,
dt2 - add_months( dt1, trunc(months_between(dt2,dt1)) ) days
from
(
select date '2012-01-01' dt1, date '2012-03-25' dt2 from dual union all
select date '2012-01-01' dt1, date '2013-01-01' dt2 from dual union all
select date '2012-01-01' dt1, date '2012-01-01' dt2 from dual union all
select date '2012-02-28' dt1, date '2012-03-01' dt2 from dual union all
select date '2013-02-28' dt1, date '2013-03-01' dt2 from dual union all
select date '2013-02-28' dt1, date '2013-04-01' dt2 from dual
) sample_data;
Hope it helps.

MySQL Query to select data from last week?

Hi I have a table with a date field and some other information.
I want to select all entries from the past week, (week start from Sunday).
table values:
id date
2 2011-05-14 09:17:25
5 2011-05-16 09:17:25
6 2011-05-17 09:17:25
8 2011-05-20 09:17:25
15 2011-05-22 09:17:25
I want to select all ids from last week, expected output is 5, 6, 8.
(id 2 not in last week, and id 15 is in current week.)
How to write and SQL Query for the same.
select id from tbname
where date between date_sub(now(),INTERVAL 1 WEEK) and now();
SELECT id FROM tbl
WHERE date >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY
AND date < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY
SELECT id FROM table1
WHERE YEARWEEK(date) = YEARWEEK(NOW() - INTERVAL 1 WEEK)
I use the YEARWEEK function specifically to go back to the prior whole calendar week (as opposed to 7 days before today). YEARWEEK also allows a second argument that will set the start of the week or determine how the first/last week of the year are handled. YEARWEEK lets you to keep the number of weeks to go back/forward in a single variable, and will not include the same week number from prior/future years, and it's far shorter than most of the other answers on here.
Simplified form:
Last week data:
SELECT id FROM tbl
WHERE
WEEK (date) = WEEK( current_date ) - 1 AND YEAR( date) = YEAR( current_date );
2 weeks ago data:
SELECT id FROM tbl
WHERE
WEEK (date) = WEEK( current_date ) - 2 AND YEAR( date) = YEAR( current_date );
SQL Fiddle
http://sqlfiddle.com/#!8/6fa6e/2
You can make your calculation in php and then add it to your query:
$date = date('Y-m-d H:i:s',time()-(7*86400)); // 7 days ago
$sql = "SELECT * FROM table WHERE date <='$date' ";
now this will give the date for a week ago
Probably the most simple way would be:
SELECT id
FROM table
WHERE date >= current_date - 7
For 8 days (i.e. Monday - Monday)
PLEASE people... 'Last week' like the OP asked and where I was looking for (but found none of answers satisfying) is THE LAST WEEK.
If today is Tuesday, then LAST WEEK is Monday A WEEK AGO to Sunday A WEEK AGO.
So:
WHERE
WEEK(yourdate) = WEEK(NOW()) - 1
Or for ISO weeks:
WHERE
WEEK(yourdate, 3) = WEEK(NOW(), 3) - 1
If you're looking to retrieve records within the last 7 days, you can use the snippet below:
SELECT date FROM table_name WHERE DATE(date) >= CURDATE() - INTERVAL 7 DAY;
Here is a way to get last week, month, and year records in MySQL.
Last Week
SELECT UserName, InsertTime
FROM tblaccounts
WHERE WEEK(InsertTime) = WEEK(NOW()) - 1
AND MONTH(InsertTime) = MONTH(NOW())
AND YEAR(InsertTime) = YEAR(NOW())
Last Month
SELECT UserName, InsertTime
FROM tblaccounts
WHERE MONTH(InsertTime) = MONTH(NOW()) - 1
AND YEAR(InsertTime) = YEAR(NOW())
Last YEAR
SELECT UserName, InsertTime
FROM tblaccounts
WHERE YEAR(InsertTime) = YEAR(NOW()) - 1;
You'll need to calc which day relative to today is Sunday in your middleware (php, python, etc.)*
Then,
select id
from table
where date >= "$sunday-date" + interval 7 DAY
may be a way to get sunday's date relative to today in MySQL as well; that would be arguably the cleaner solution if not too expensive to perform
It can be in a single line:
SELECT * FROM table WHERE Date BETWEEN (NOW() - INTERVAL 7 DAY) AND NOW()
A simple way can be this one, this is a real example from my code and works perfectly:
where("actions.created_at >= DATE_SUB(CURDATE(), INTERVAL 1 WEEK)")
For more example Like last month, last year, last 15 days, last 3 months
Fetch Last WEEK Record
Using the below MySQL query for fetching the last week records from the mysql database table.
SELECT name, created_at
FROM employees
WHERE
YEARWEEK(`created_at`, 1) = YEARWEEK( CURDATE() - INTERVAL 1 WEEK, 1)
The above query will not work.
After the where clause, if we can not CAST the column value, then it will not work. You should cast the column value.
e.g.:
SELECT.....
WHERE CAST( yourDateColumn AS DATE ) > DATEADD( DAY, -7, CAST( GETDATE() AS DATE )
SELECT id FROM tb1
WHERE
YEARWEEK (date) = YEARWEEK( current_date -interval 1 week )
I often do a quick "last week" check as well and the following tends to work well for me and includes today.
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = Getdate() - 7 /* Seven Days Earlier */
SET #EndDate = Getdate() /* Now */
SELECT id
FROM mytable
WHERE date BETWEEN #StartDate AND #Enddate
If you want this to NOT include today just subtract an extra day from the #EndDate. If I select these two variables today get
#StartDate 2015-11-16 16:34:05.347 /* Last Monday */
#EndDate 2015-11-23 16:34:05.347 /* This Monday */
If I wanted Sunday to Sunday I would have the following.
SET #StartDate = Getdate() - 8 /* Eight Days Earlier */
SET #EndDate = Getdate() - 1 /* Yesterday */
#StartDate 2015-11-15 16:34:05.347 /* Previous Sunday */
#EndDate 2015-11-22 16:34:05.347 /* Last Sunday */
WHERE yourDateColumn > DATEADD(DAY, -7, GETDATE()) ;
You can also use it esay way
SELECT *
FROM inventory
WHERE YEARWEEK(`modify`, 1) = YEARWEEK(CURDATE(), 1)
i Use this for the week start from SUNDAY:
SELECT id FROM tbl
WHERE
date >= curdate() - INTERVAL DAYOFWEEK(curdate())+5 DAY
AND date < curdate() - INTERVAL DAYOFWEEK(curdate())-2 DAY
try this
WHERE trunc(DATE) <= (trunc (sysdate) -5) AND trunc(DATE) >= (trunc (sysdate) -12)
-5 is 5 days back from system date ,, -12 is 12 days back from system date for this example wednesday / or sednesday to wednesday cant recall.
Try this:
Declare #Daytype varchar(15),
#StartDate datetime,
#EndDate datetime
set #Daytype = datename(dw, getdate())
if #Daytype= 'Monday'
begin
set #StartDate = getdate()-7
set #EndDate = getdate()-1
end
else if #Daytype = 'Tuesday'
begin
set #StartDate = getdate()-8
set #EndDate = getdate()-2
end
Else if #Daytype = 'Wednesday'
begin
set #StartDate = getdate()-9
set #EndDate = getdate()-3
end
Else if #Daytype = 'Thursday'
begin
set #StartDate = getdate()-10
set #EndDate = getdate()-4
end
Else if #Daytype = 'Friday'
begin
set #StartDate = getdate()-11
set #EndDate = getdate()-5
end
Else if #Daytype = 'Saturday'
begin
set #StartDate = getdate()-12
set #EndDate = getdate()-6
end
Else if #Daytype = 'Sunday'
begin
set #StartDate = getdate()-13
set #EndDate = getdate()-7
end
select #StartDate,#EndDate
You can try this one. it worked for me :
where date(createdtime) <= date(curdate())-7
In the the above code createdtime is database field name, as individuals this name could vary.
If you already know the dates then you can simply use between, like this:
SELECT id
FROM `Mytable`
where MyDate BETWEEN "2011-05-15" AND "2011-05-21"