The goal is to return a set of dates that correspond to the day of week requested.
For example: every other Monday between 2018-08-13 and 2018-12-31.
The following statement returns all dates and works great
select * from
(select adddate('2010-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) DATES from
(select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where DATES between '2018-08-13' and '2018-12-31'
and dayname(DATES) ='MONDAY'
So to return every other MONDAY I added the following
HAVING DATES % 2 = 0
I assumed that by taking MOD of dates it would, in this case return every MONDAY that met this criteria. Well it does not work. I've tried all sorts of combos but not getting it.
Any ideas?
Dates are a complex data structure and the details of how they are stored and manipulated vary between DBMSs. Most often you can't treat them as numeric data types as you are trying to do here. Instead you should calculate the number of days between the date of interest and a fixed date then you can take the modulus of that number: for example:
select * from
(select adddate('2010-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) DATES from
(select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where DATES between '2018-08-13' and '2019-01-31'
and dayname(DATES) ='MONDAY'
and datediff(dates,'2018-08-13') % 2 = 0
order by dates
Alternatively since every other Monday is 14 days apart you could use modulus 14 and drop the dayname(DATES) ='MONDAY' predicate:
select * from
(select adddate('2010-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) DATES from
(select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where DATES between '2018-08-13' and '2019-01-31'
and datediff(dates,'2018-08-13') % 14 = 0
order by dates
This can be made to work with a few little modifications as follows:
SELECT * FROM
(
SELECT ADDDARE('1970-01-01', t4*10000 + t3*1000 + t2*100 + t1*10 + t0) selected_date FROM
(SELECT 0 t0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t0,
(SELECT 0 t1 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1,
(SELECT 0 t2 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2,
(SELECT 0 t3 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3,
(SELECT 0 t4 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t4
) v
WHERE
selected_date between '2018-08-08' AND '2018-10-19'
AND DAYOFWEEK(selected_date) = 2
AND WEEK(selected_date) % 2 = WEEK('2018-08-08') % 2
The idea is that it will include the Monday of the week that the selection period begins from. So, it doesn't matter whether the starting week is odd or even, you'd always get alternate Mondays without having to worry about specifying 0 or 1 for the result of modulo operation.
Related
I am trying to do two subqueries to populate my table with two columns. wk_start and wk_end.
Goal is to populate it with a specific range of date.
I've tried cross join but still having duplicates the same as this one
Here is my code
insert into bfs_dw.mpt_calendar (wk_start, wk_end)
select
ter.wk_start,
ter1.wk_end
from
(select * from
(select ADDDATE('2022-01-03', 7*(t4*10000 + t3*1000 + t2*100 + t1*10 + t0)) wk_start from
(select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where wk_start < '2024-01-03'
order by wk_start ) ter
inner JOIN
(select * from
(select ADDDATE('2022-01-09', 7*(t4*10000 + t3*1000 + t2*100 + t1*10 + t0)) wk_end from
(select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where wk_end < '2024-01-03'
order by wk_end ) ter1 ON 1 = 1
Output display below. which has a lot of duplicates after the insert.
What I am trying to do is this expected result, which has no duplicates once inserted:
Note: the two subqueries works well. Its output was the last image posted here.
Use the first subquery to get wk_start, and add 6 days to get the wk_end
insert into bfs_dw.mpt_calendar (wk_start, wk_end)
select wk_start, wk_start + INTERVAL 6 DAY wk_end from
(select ADDDATE('2022-01-03', 7*(t4*10000 + t3*1000 + t2*100 + t1*10 + t0)) wk_start from
(select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where wk_start < '2024-01-03'
My following query showing data count even when there is no data for that date.
SELECT c.date AS DATE, COUNT(s.insertTime) AS tot_cnt FROM (SELECT ADDDATE('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)
DATE FROM (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t0,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t4 ) c
LEFT JOIN `access_log` s ON c.date = DATE(s.insertTime)
WHERE UNIX_TIMESTAMP(c.date) BETWEEN 1563733801 AND 1564338599 GROUP BY c.date ORDER BY c.date;
But when I add userId=8, it skips all date range which don't have any value
SELECT c.date AS DATE, COUNT(s.insertTime) AS tot_cnt FROM (SELECT ADDDATE('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i)
DATE FROM (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t0,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t4 ) c
LEFT JOIN `access_log` s ON c.date = DATE(s.insertTime)
WHERE UNIX_TIMESTAMP(c.date) BETWEEN 1563733801 AND 1564338599 AND userId=8 GROUP BY c.date ORDER BY c.date;
I need all date even they don't have value and also when apply userId=8 to filter records.
Apply the condition in the ON clause and not the WHERE clause:
ON c.date = DATE(s.insertTime) AND userId=8
so the LEFT JOIN returns the non matching rows.
I have a questions when I try to create a table in mysql.
The syntax is below:
create table abc as
(select * from
(select adddate('2010-01-01',t5.i*100000 +t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) selected_date from
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t5) v
where selected_date between '2010-01-01' and '2020-12-31');
It seems that I create the table successfully, but I cannot find this table in the tables list or even in the schema.
Could someone who has expertise in SQL help me check the syntax?
So we all know that we can get the week number of a date by using the week() function. My question is how to display the dates of that particular week, except the Sunday date?
To illustrate..
Based from the above example, what I want to display is..
2009-05-17
2009-05-18
2009-05-19
2009-05-20
2009-05-21
2009-05-22
How do I query this?
SET #GivenDate ='2016-05-27';
SET #YearNum = YEAR(#GivenDate);
SET #WeekNum=WEEK(#GivenDate);
select selected_date,weekday(selected_date) AS WeeKDate
from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) selected_date from
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where YEAR(selected_date)=#YearNum
AND WEEK(selected_date)=#WeekNum
AND WEEKDAY(selected_date)<> 6;
This question already has answers here:
Get a list of dates between two dates
(23 answers)
Closed 9 years ago.
I want list of dates lies between two dates by select query. For example:
If i give '2012-02-10' and '2012-02-15' I need the result.
date
----------
2012-02-10
2012-02-11
2012-02-12
2012-02-13
2012-02-14
2012-02-15
How can i get?
Try:
select * from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) selected_date from
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where selected_date between '2012-02-10' and '2012-02-15'
-for date ranges up to nearly 300 years in the future.
[Corrected following a suggested edit by UrvishAtSynapse.]
set #i = -1;
SELECT DATE(ADDDATE('2012-02-10', INTERVAL #i:=#i+1 DAY)) AS date FROM `table`
HAVING
#i < DATEDIFF('2012-02-15', '2012-02-10')
This will return your result set exactly as prescribed. This query only requires you change the two different dates in datediff and adddate.
The accepted answer didn't work for me in MySQL 5.5.
I updated the query to work for me:
select * from
(select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) selected_date from
(select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
where selected_date between '2012-02-10' and '2012-02-15'
Take a look at this post : Get a list of dates between two dates
Check the stored procedure that Ron Savage did, this seems to correspond to what you need !
You can create a table containing all the dates you might ever need to use:
date
2000-01-01
2000-01-02
2000-01-03
...etc..
2100-12-30
2100-12-31
Then query that table as follows:
SELECT date
FROM dates
WHERE date BETWEEN '2012-02-10' AND '2012-02-15'
SELECT * FROM tablexxx WHERE datecol BETWEEN '2012-02-10' AND '2012-02-15';