how to combine or join 2 MySQL queries together - mysql

I have 2 following queries return the same columns:
first query is slightly modified one I found here in different post returning all day of the current month:
select null as id,
a.day, 0 as was_present,
0 as was_late,
0 as left_earlier,
null as student_id
from (
select
last_day(NOW())
- INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as day
from (
select 0 as a
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
) as a
cross join
(
select 0 as a
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
) as b
cross join
(
select 0 as a
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
) as c
) as a
where a.day between DATE_FORMAT(NOW() ,'%Y-%m-01') AND NOW()
order by a.day
while the second is returning attendance data from the real table like this:
select *
from student_attendance
where student_id = ?1
and (date between DATE_FORMAT(NOW() ,'%Y-%m-01') AND NOW())
Sample data from second query look like this:
2 2019-10-01 1 0 0 5
3 2019-10-02 1 0 0 5
4 2019-10-03 1 0 0 5
5 2019-10-04 1 0 0 5
Now my question is how to combine them together to return only unique days of the month (1 record per day) where the real record from second query replaces fake record in first query when it exist. I tried to use union but it return duplicates.
Again, using union doesn't work, here is what it returns:
2019-10-01 0 0 0
2 2019-10-01 1 0 0 5
2019-10-02 0 0 0
3 2019-10-02 1 0 0 5
4 2019-10-03 1 0 0 5
2019-10-03 0 0 0
2019-10-04 0 0 0
5 2019-10-04 1 0 0 5
2019-10-05 0 0 0

You could use a temporary table then do a LEFT JOIN to it:
CREATE TEMPORARY TABLE days
select a.day
from (
select last_day(NOW()) - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as
day
from (select 0 as a 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) as a
cross join (select 0 as a 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) as b
cross join (select 0 as a 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) as c
) a where a.day between DATE_FORMAT(NOW() ,'%Y-%m-01') AND NOW() order by
a.day;
SELECT
id, days.`day`, was_present, was_late, left_earlier, student_id
FROM days
LEFT JOIN student_attendance sa ON days.`day` = sa.`day`;

try with the UNION between the second query and the rows of the first query with date not present in the second query, something like this:
select *
from student_attendance
where student_id = ?1 and (date between DATE_FORMAT(NOW() ,'%Y-%m-01') AND NOW())
UNION
select null as id,
a.day, 0 as was_present,
0 as was_late,
0 as left_earlier,
null as student_id
from (
select last_day(NOW()) - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as day
from (
select 0 as a
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
) as a
cross join
(
select 0 as a
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
) as b
cross join
(
select 0 as a
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
) as c
) as a
where a.day between DATE_FORMAT(NOW() ,'%Y-%m-01') AND NOW()
and a.day NOT IN (
select date
from student_attendance
where student_id = ?1 and (date between DATE_FORMAT(NOW() ,'%Y-%m-01') AND NOW())
)
order by a.day

Related

Get dates lies between two date ranges, as per the Day of week in my sql

I have fromDate, toDate and dayOfWeek in mysql. I want all the dates that lies on the particular dayofWeek and lies between fromDate and toDate.
eg
fromDate- '2021-09-01 00:00:00'
toDate- '2021-09-30 00:00:00'
dayOfWeek(4,5) i.e thurday and Friday
output
output
2021-09-02
2021-09-03
2021-09-01
2021-09-10
2021-09-16
2021-09-17
2021-09-23
2021-09-24
2021-09-30
I am using MYSQLWORKBENCH 8.0
here for you
select * from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) as 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 '2021-09-01' and '2021-09-30'
having WEEKDAY(selected_date) in (3,4)
ORDER BY selected_date ASC;
0 is monday , 3 is thurday ...
from this post
Another way to get all Thursday and Friday between two dates. I use LAST_DAY() function (last month day) to set the end of the interval, but you can hard code a specific date:
WITH RECURSIVE days AS (SELECT '2021-09-01' as day
UNION ALL
SELECT DATE_ADD(day, INTERVAL 1 DAY)
FROM days
WHERE day < LAST_DAY(day))
SELECT *
FROM days
WHERE weekday(day) IN (3,4);
Output:
day
2021-09-02
2021-09-03
2021-09-09
2021-09-10
2021-09-16
2021-09-17
2021-09-23
2021-09-24
2021-09-30

Problem about Show Data Filter By Date In MySQL

I have a table Order:
id total_amount date_order
1 12.000 2018-09-01
2 10.000 2018-09-01
3 5.000 2018-09-03
4 2.000 2018-09-05
I have query SUM data group by date:
select SUM(total_amount) as 'total', DATE(date_order) as 'date'
from Order
where date_order >= '2018-09-01' and date_order <= '2018-09-06'
group by (date_order)
It shows:
total date
22.000 2018-09-01
5.000 2018-09-03
2.000 2018-09-05
Because data in 2018-09-02 and 2018-09-04 have no data so It's not show in result. But I want query to show table with expect result:
total date
22.000 2018-09-01
0 2018-09-02
5.000 2018-09-03
0 2018-09-04
2.000 2018-09-05
Every can help me write query to show like expect result ?
Create another table to join on.
It could be a table of dates, such as all date from 2000-01-01 until 2099-12-31...
SELECT
dt.`date`,
SUM(total_amount) as `total`
FROM
yourDatesTable AS dt
LEFT JOIN
Order AS o
ON o.`date_order` = dt.`date`
WHERE
dt.`date` >= '2018-09-01'
AND dt.`date` < '2018-09-08'
GROUP BY
dt.`date`
ORDER BY
dt.`date`
Or it could be a numbers table with values from -1023 to +1024 (or some other useful range)...
SELECT
n.id,
'2018-09-01' + INTERVAL n.id DAYS,
SUM(total_amount) as `total`
FROM
yourNumbersTable AS n
LEFT JOIN
Order AS o
ON o.`date_order` = '2018-09-01' + INTERVAL n.id DAYS
WHERE
n.id >= 0
AND n.id < 8
GROUP BY
n.id
ORDER BY
n.id
generate date and join with ordere table
select SUM(O.total_amount) as total, DATE(gen_date) as oreder_date
from
(
select * from
(select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) gen_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 gen_date between '2018-09-01' and '2018-09-30'
) as t1 left join `Order` O on t1.gen_date= DATE(O.date_order)
where gen_date >= '2018-09-01' and gen_date <= '2018-09-06'
group by oreder_date

Get date in mysql recursive 'x' week

I have got the query which will give me all the dates which are Monday and Tuesday
SELECT a.Date AS dat_e FROM ( SELECT DATE_ADD( '2018-01-17' , INTERVAL (1) DAY ) + INTERVAL( a.a + ( 10 * b.a ) + ( 100 * c.a ) ) DAY AS DATE FROM ( SELECT 0 AS a 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 ) AS a CROSS JOIN ( SELECT 0 AS a 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 ) AS b CROSS JOIN ( SELECT 0 AS a 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 ) AS c )a HAVING DAYOFWEEK(dat_e) IN ( 2,3)
I want to get the dates after 'x' weeks, ie: after 1,2 or 3 weeks. and the dates should be Monday and Tuesday

Show all dates between, even if no result In group by

SELECT Count(Phq_2) as Phq_2, Date(created) as created
FROM `survey`
WHERE Phq_2 != ''
GROUP BY Date(created)
ORDER BY Date(created) ASC
Showing this
Expected Result
you can create a list of dates where you can use to list and join on your table. table c on the query below is the date table.
SELECT c.date,
COUNT(s.phq_2)
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 `survey` s
ON c.date = s.created
WHERE s.phq_2 != ''
AND c.date BETWEEN '2017-08-30' AND '2017-09-06'
GROUP BY c.date
ORDER BY c.date
Result
date COUNT(s.phq_2)
2017-08-30 1
2017-08-31 1
2017-09-01 0
2017-09-02 0
2017-09-03 0
2017-09-04 0
2017-09-05 1
2017-09-06 6
if you want the dates fixed for WHERE c.date BETWEEN '2017-08-30' AND '2017-09-06', you can use the resulting MIN() and MAX() of column created from your table in a sub-query

get Mondays between two dates mysql

I want to get the Mondays between two dates with a select statement, but I only have searched in sql server.
I have tried this, but it doesn´t work:
SELECT DATE_ADD('2017-01-01', INTERVAL ROW DAY) AS Date
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('2017-01-01', INTERVAL ROW DAY) BETWEEN '2017-01-01' AND '2017-12-31'
AND DAYOFWEEK(DATE_ADD('2017-01-01', INTERVAL ROW DAY)) = 2
This query only gives me the Monday´s date for one month.
I hope that you can help me
Regards!
If you really want to solve this SQL only, you have to delve a bit deeper and generate a sequence of days, this is by far the most difficult side task to solve this. Besides this, as you have already guessed, you can use DAYOFWEEK or WEEKDAY to get your desired days.
SELECT *
FROM (
SELECT DATE_ADD('2013-01-01',
INTERVAL n4.num*1000+n3.num*100+n2.num*10+n1.num DAY ) AS DATE
FROM (
SELECT 0 AS num
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
) AS n1,
(
SELECT 0 AS num
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
) AS n2,
(
SELECT 0 AS num
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
) AS n3,
(
SELECT 0 AS num
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
) AS n4
) AS a
WHERE DATE >= '2017-01-01' AND DATE < NOW()
AND WEEKDAY(DATE) = 0
ORDER BY DATE
Some other RDBMS have inbuild functions for that.
If would be way easier if you have a calendar table where all dates are already present.
I think that this solution will work with better performance than previous
SET #date_start = date('2019-07-06');
SET #date_end = date('2019-09-18');
SELECT CASE WHEN MOD(DAYOFWEEK(#date_start), 7) <= 2 AND
MOD(DAYOFWEEK(#date_start), 7) + DATEDIFF(v.selected_date, #date_start) - 7 * FLOOR(DATEDIFF(v.selected_date, #date_start) / 7) >= 2 OR
MOD(DAYOFWEEK(#date_start), 7) > 2 AND
MOD(DAYOFWEEK(#date_start), 7) + DATEDIFF(v.selected_date, #date_start) - 7 * FLOOR(DATEDIFF(v.selected_date, #date_start) / 7) >= 9 THEN 1 ELSE 0 END
+ FLOOR(DATEDIFF(v.selected_date, #date_start) / 7) num_of_mo
, #date_start start_date,v.selected_date end_date
FROM (select adddate(#date_start,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 v.selected_date <= #date_end;