I need to find number of Sundays between two dates using mysql. I know how to do it using PHP But i need it to be calculated using mysql.
SET #START_DATE = '2014-01-22';
SET #END_DATE = '2014-06-29';
SELECT
ROUND((
(unix_timestamp(#END_DATE) - unix_timestamp(#START_DATE) ) /(24*60*60)
-7+WEEKDAY(#START_DATE)-WEEKDAY(#END_DATE)
)/7)
+ if(WEEKDAY(#START_DATE) <= 6, 1, 0)
+ if(WEEKDAY(#END_DATE) >= 6, 1, 0) as Sundays;
Solution consist of 2 parts:
counts number of full weeks (ROUND part), obviously you'll have 7 Sundays in 7 weeks.
count days that are included into the not full week parts (first or last)
If you'll need to use it more than once you can wrap it into the function:
DROP function IF EXISTS `count_weekdays`;
DELIMITER $$
CREATE FUNCTION `count_weekdays` (startDate date, endDate date, wd int)
RETURNS INTEGER
BEGIN
RETURN ROUND((
(unix_timestamp(endDate) - unix_timestamp(startDate) ) /(24*60*60)
-7+WEEKDAY(startDate)-WEEKDAY(endDate)
)/7)
+ if(WEEKDAY(startDate) <= wd, 1, 0)
+ if(WEEKDAY(endDate) >= wd, 1, 0);
END$$
DELIMITER ;
Then you will be able to use it like this:
SET #START_DATE = '2018-07-03';
SET #END_DATE = '2018-07-28';
select
count_weekdays(#START_DATE, #END_DATE, 6) as Sundays,
count_weekdays(#START_DATE, #END_DATE, 5)
+ count_weekdays(#START_DATE, #END_DATE, 6) as weekends;
Where 6 ~ number of weekday stands for Sunday, 5 ~ Saturday.
http://sqlfiddle.com/#!2/d41d8/50695
Maybe there will be no code on this link someday so I posted it here.
the upper link will show the number of the day and with date of the sundays. if you want to find any other day change the 1 at last to 2 for monday
select DATE_ADD('2012-12-15', INTERVAL ROW DAY) as Date,
row+1 as DayOfMonth from (
SELECT #row := #row + 1 as row FROM
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6) t1,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6) t2,
(SELECT #row:=-1) t3 limit 31
) b
where
DATE_ADD('2012-12-01', INTERVAL ROW DAY)
between '2012-12-01' and '2012-12-31'
and
DAYOFWEEK(DATE_ADD('2012-12-01', INTERVAL ROW DAY))=1
Does this work...
SELECT FLOOR(
(DATEDIFF(
'#enddate'
,'#startdate' + INTERVAL
LENGTH(SUBSTRING_INDEX('654321',WEEKDAY('#startdate'),1))
DAY) + 1)/7) + 1 x;
SELECT a.StartDate, a.EndDate,
(DAY(EndDate - StartDate) / 7)
+ iif(DAY(EndDate - StartDate)%7 + DATEPART(DW, StartDate) > 8 , 1, 0)
Sundays FROM
(SELECT GETDATE() StartDate, DATEADD(DAY, 11, GETDATE()) EndDate) a
This is useful for multiple start and end dates in a table.
no need of variables and loops!
How it works: determines the number of full weeks between start and end date,
determines the days less than a week and add with the start day index(1,2,3,4,5,6,7) if that value Greater than count 8(means which is Sunday !)
For Sunday week day index is 1, day 8 is nothing but index 1.
SELECT COUNT(*) FROM table_name
WHERE column BETWEEN 'start_date' AND 'end_date'
AND WEEKDAY(date) = 6;
Refer this, mysql have a function dayofweek, you can easily calculate starting week day and after that divide the number of days with 7:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_dayofweek
OR
SELECT COUNT(*) FROM table_name
WHERE date_column_of_table_name BETWEEN '2013-01-11' AND '2013-03-01'
AND WEEKDAY(date_column_of_table_name) = 6
Try this
select count(DAYNAME(your_date_field)='Sunday') as sunday from tbl_name where your_date_field between 'date1' AND 'date2'
Related
I am trying to split a specific date range into chunks of 3 days to find the number of records per each three day chunks.
For example, assume I have this table:
User
Minimum Date
Maximum Date
Consecutive Days
1
09/20/2021
09/29/2021
10
And I want to produce this table:
User
Minimum Date
Maximum Date
1
09/20/2021
09/22/2021
1
09/23/2021
09/25/2021
1
09/26/2021
09/28/2021
The reason I ended it off there is because the remaining days are not enough to make up 3 days.
You need in something like
WITH RECURSIVE
cte AS (
SELECT User,
MinimumDate,
MinimumDate + INTERVAL 2 DAY MaximumDate, -- N-1
MaximumDate FinalDate
FROM sourcetable
WHERE MinimumDate + INTERVAL 2 DAY <= MaximumDate -- N-1
UNION ALL
SELECT User,
MinimumDate + INTERVAL 3 DAY, -- N
MinimumDate + INTERVAL 5 DAY, -- 2*N-1
FinalDate
FROM cte
WHERE MinimumDate + INTERVAL 5 DAY <= FinalDate -- 2*N-1
)
SELECT User,
MinimumDate,
MaximumDate
FROM cte
ORDER BY 1, 2;
or (not tested)
WITH RECURSIVE
cte1 AS ( SELECT (MAX(DATEDIFF(MaximumDate, MinimumDate)) DIV 3) - 1 maxrange
FROM sourcetable ),
cte2 AS ( SELECT 0 num
UNION ALL
SELECT num + 1 FROM cte2 WHERE num < maxrange )
SELECT User,
MinimumDate + INTERVAL 3 * num DAY MinimumDate,
MinimumDate + INTERVAL 2 + 3 * num DAY MaximumDate
FROM sourcetable
JOIN cte2 ON MinimumDate + INTERVAL 3 * num DAY <= MaximumDate
ORDER by 1,2
I'm trying to get all my result of last 30 days, getting 0 when the count is 0.
My query is:
SELECT substring(mc.publication_date, 1, 10) AS title, count(mc.id) AS quantity
FROM mymyv_cards mc
WHERE mc.publicated = 1 AND STR_TO_DATE(substring(mc.publication_date, 1, 10), "%d-%m-%Y") BETWEEN CURDATE() - INTERVAL 30 DAY AND CURDATE()
GROUP BY substring(mc.publication_date, 1, 10)
And I get this:
But I would like the result was like:
06-04-2021 --> 1
07-04-2021 --> 2
08-04-2021 --> 0
09-04-2021 --> 0
10-04-2021 --> 0
............... etc etc
I don't know how to do that, can you help me?
What you need is a list of all the dates. If you don't have one handy, you can create on using a recursive CTE:
with recursive dates as (
select curdate() as dte, 1 as lev
union all
select dte - interval 1 day, lev + 1
from dates
where lev < 30
)
select *
from dates;
Then you incorporate this into your query with a left join:
with recursive dates as (
select curdate() as dte, 1 as lev
union all
select dte - interval 1 day, lev + 1
from dates
where lev < 30
)
select d.dte, count(mc.id)
from dates d left join
mymyv_cards mc
on mc.publicated = 1 and
str_to_date(left(mc.publication_date, 10), '%d-%m-%Y') >= d.dte and
str_to_date(left(mc.publication_date, 10), '%d-%m-%Y') < d.dte + interval 1 day
group by d.dte;
Note that a column called publication_date should be stored with the value as a date not as a string. You should really fix the data model so the data is stored using the correct types.
Also, you might have a numbers table or calendar table lying around in your database. If so, you can use that instead of the recursive CTE.
I want to show date range of week by passing a variable which contains year and month i.e 2016-07 like this in mysql how could i achieve this:
for eg: if i pass 2016-07 then my output should look like this:
2016-07-03 to 2016-07-10 || 2016-07-11 to 2016-07-17
and so on
There are several parts to solving this problem, when you go to solve it in MySQL.
One is to decide whether your weeks start on Sundays or Mondays. That's a locale-specific business rule. In locales formerly part of the British Empire (USA, India) it's usually Sunday. In other places, it's Monday.
So we'll need a function like this: firstDayOfWeek(date). More about that in a moment.
Once we have that, we'll need a way to get the last day of the month in question. That's easy; it's a built-in MySQL function. LAST_DAY(date)
You have said you'll specify the month in question with a string like 1941-12. We'll need to turn that into a DATE object. That can be done like this:
STR_TO_DATE(CONCAT(`1941-12`, `-01'), '%Y-%m-%d')
We need a virtual table with the integers from 0 to 4. Let's call that table seq_0_to_4. We pick that range of integers because no months have more than five Sundays (or Mondays). More on that later.
OK, these are the conceptual building blocks. Let's use them.
The first day of the week derived from the last day of the month is
SET #month := '1941-12';
SET #first_day_of_month := STR_TO_DATE(CONCAT(`1941-12`, `-01'), '%Y-%m-%d')
SET #seed : =FirstDayOfWeek(LAST_DAY(first_day_of_month));
Then you need four five consecutive week-starting days the last of which is #seed.
SELECT #seed - INTERVAL (7*seq.seq) first_day_of_week
FROM seq_0_to_4
Next you need to limit that to days in your month.
SELECT first_day_of_week,
first_day_of_week + INTERVAL 6 DAY last_day_of_week
FROM (
SELECT #seed - INTERVAL (7*seq.seq) first_day_of_week
FROM seq_0_to_4
) w
WHERE first_day_of_week >= #first_day_of_month
ORDER BY first_day_of_week
That gives you a table of rows, one for each week beginning in the month. If you want to exclude weeks in which the last weekday is in the next month, change your WHERE to
WHERE first_day_of_week >= #first_day_of_month
AND first_day_of_week + INTERVAL 6 DAY <= #seed
Finally, to get the exact string format you specified in your question, wrap that query in this:
SELECT GROUP_CONCAT (
CONCAT(first_day_of_week, ' to ', last_day_of_week)
SEPARATOR ' || '
ORDER BY first_day_of_week)
FROM (
SELECT first_day_of_week,
first_day_of_week + INTERVAL 6 DAY last_day_of_week
FROM (
SELECT #seed - INTERVAL (7*seq.seq) first_day_of_week
FROM seq_0_to_4
) w
WHERE first_day_of_week >= #first_day_of_month
) x
That's it.
I promised to describe FirstDayOfWeek(dt). Here it is.
FROM_DAYS(TO_DAYS(dt) -MOD(TO_DAYS(dt) -1, 7))
It's a bit of a magic spell, but it works. If your weeks start Mondays, it is this.
FROM_DAYS(TO_DAYS(dt) -MOD(TO_DAYS(dt) -2, 7))
I promised to describe seq_0_to_4. If you're using the MariaDB fork of MySQL, it's built in. If you're using the Sun / Oracle fork, you define it like this.
(SELECT 0 AS seq UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) seq_0_to_4
Putting it all together:
SET #month := '1941-12';
SET #first_day_of_month := STR_TO_DATE(CONCAT(`1941-12`, `-01'), '%Y-%m-%d');
SET #seed := FROM_DAYS(TO_DAYS(LAST_DAY(first_day_of_month))
-MOD(TO_DAYS(LAST_DAY(first_day_of_month)) -1, 7));
SELECT GROUP_CONCAT (
CONCAT(first_day_of_week, ' to ', last_day_of_week)
SEPARATOR ' || '
ORDER BY first_day_of_week)
FROM (
SELECT first_day_of_week,
first_day_of_week + INTERVAL 6 DAY last_day_of_week
FROM (
SELECT #seed - INTERVAL (7*seq.seq) first_day_of_week
FROM (SELECT 0 AS seq UNION SELECT 1 UNION SELECT 2
UNION SELECT 3 UNION SELECT 4
) seq
) w
WHERE first_day_of_week >= #first_day_of_month
) x
It's unreasonably complex (the technical term is a freakin' hairball) to solve your problem in pure MySQL-dialect SQL, but it's possible.
Probably is too late but i figured out this using Common Table expressions in MYSQL 8.0.2
WITH RECURSIVE
Years(y) AS
(
SELECT 2020
UNION ALL
SELECT y + 1 FROM Years WHERE y < 2021
),
Days (d) AS
(
SELECT 1
UNION ALL
SELECT d + 1 FROM Days WHERE d < 366
)
SELECT
y AS Year,
MONTH(MakeDate(y,d)) AS Month,
WEEK(MakeDate(y,d))+1 -WEEK(TIMESTAMPADD(MONTH,MONTH(MakeDate(y,d))-1,MakeDate(y,1))) AS Week,
Min(MakeDate(y,d)) AS StartDate,
timestampadd(second,-1,timestampadd(day,1,MAx(MakeDate(y,d)))) AS EndDate
FROM Years,Days
WHERE Year(MakeDate(y,d)) <= y
GROUP BY y, MONTH(MakeDate(y,d)),WEEK(MakeDate(y,d))+1 -WEEK(TIMESTAMPADD(MONTH,MONTH(MakeDate(y,d))-1,MakeDate(y,1)))
ORDER BY 1,2,3
There some kind to get the Date if you have only the Day of Week, Week number, Month and Year with MySQL?
Example:
I Want to know which day is with this parameters:
Year : 2014
Month : Setember (09)
Week number of Year : 37 OR Week number in Setember : 3
Day of Week: Thursday
The Answer is '2014-09-18'
Using Barmars suggestion you can build a calendar of the year on the fly and check it against your constraints about that:
SET #year := 2014; -- set the year of the constraints
SET #week := 37; -- the week
SET #day_of_week := 5; -- the day of the week (numerical)
-- build the first of the wanted year as supposed by Barmar
SET #first_of_year = STR_TO_DATE(CONCAT(#year, '-01-01'), '%Y-%m-%d');
SELECT
#first_of_year + INTERVAL t.n DAY the_date
FROM (
SELECT
a.N + b.N * 10 + c.N * 100 AS n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) c
ORDER BY n
) t
WHERE
t.n < TIMESTAMPDIFF(DAY, #first_of_year, #first_of_year + INTERVAL 1 YEAR)
AND
WEEK(#first_of_year + INTERVAL t.n DAY) = #week
AND
DAYOFWEEK(#first_of_year + INTERVAL t.n DAY) = #day_of_week
;
Demo
Note
The UNION generates the numbers from 0 to 399, so we can generate a calendar of the year. Now we can apply your other constraints like week in year and day of week.
I asked the same question in portuguese Stake Overflow, and they found a simple solution.
Using str_to_date, year, week number and day of week.
%Y Year, numeric, four digits
%U Week (00..53), where Sunday is the first day of the week
%W Weekday name (Sunday..Saturday)
SELECT str_to_date('201437 Thursday', '%Y%U %W');
Result:
2014-09-18 00:00:00
Portuguese Stack Overflow Answer Link : https://pt.stackoverflow.com/questions/33046/obter-data-com-dia-da-semana-n%C3%BAmero-da-semana-m%C3%AAs-e-ano/33063#33063
Thanks to everyone who helped me
I have a table with some dates. I need a query which will return the max (last) date from this table and last date of quarter this max date belongs to.
So for data i table
ID| EDATE
--+----------
1|2014-03-06
2|2014-10-12
this query should return 2014-10-12 and 2014-12-31.
As I understand you want the last day of the quarter, so 31 March, 30 June, 30 Sept, 31 Dec? So you can use the answer from Gordon Linoff and adjust it to do that.
You only need a case statement on month(date) and concat that with the year.
http://dev.mysql.com/doc/refman/5.1/de/control-flow-functions.html
str_to_date(
concat(
year(edate),
(case
when month(edate) in (1, 2, 3) then '-03-31'
when month(edate) in (4, 5, 6) then '-06-30'
when month(edate) in (7, 8, 9) then '-09-30'
else '-12-31'
end)
),
'%Y-%m-%d'
)
Getting the day of the last quarter for the date is a bit yucky, but possible. Here is a sort of brute force solution:
select edate,
str_to_date(concat(year(edate), '-', 1 + floor((month(edate) - 1)/ 3)) * 3, '-',
(case when month(edate) in (1, 2, 3, 10, 11, 12) then 31 else 30 end)),
'%Y-%m-%d'
)
from table t
order by edate desc
limit 1;
Here is a SQL Fiddle that demonstrates it.
You can use LAST_DAY to select the last day of a specific month depending on where your quarters end you may have to change the 3,6,9,12 to different months.
select t1.max_date,
(
case
when month(max_date) <= 3
then last_day(concat(year(max_date),'-3-1'))
when month(max_date) <= 6
then last_day(concat(year(max_date),'-6-1'))
when month(max_date) <= 9
then last_day(concat(year(max_date),'-9-1'))
else last_day(concat(year(max_date),'-12-1'))
end
) last_quarter_day
from (
select max(EDATE) max_date from myTable
) t1
I found the simplest answer:
SELECT MAKEDATE(YEAR(edate),1)
+ INTERVAL QUARTER(edate) QUARTER
- INTERVAL 1 DAY
This query takes the first day of year, adds quarters to it and subtracts 1 day to get the last day in wanted quarter. So the required query should look like:
SELECT MAX(edate),
MAKEDATE(YEAR(MAX(edate)),1)
+ INTERVAL QUARTER(MAX(edate)) QUARTER
- INTERVAL 1 DAY
FROM table