I've a table named userActivity where each active period is recorded.
Here's the table structure:
Table: userActivity
ID user_id start_time end_time
When a user comes into online the start time is recorded and whenever the online status is changed the end time is recorded in the corresponding row.
Now I've to generate a report where a day wise available time of the users will be shown.
Sample Input:
ID user_id start_time end_time
'1' '1' '2016-02-28 10:00:00' '2016-02-28 19:00:00'
'2' '1' '2016-02-28 22:00:00' '2016-02-29 10:00:00'
'3' '1' '2016-03-02 10:00:00' '2016-03-02 19:00:00'
'4' '1' '2016-03-02 22:00:00' '2016-03-06 19:00:00'
Expected output:
Date AvailableTime(Hours)
2016-02-28 11
2016-02-29 10
2016-03-02 11
2016-03-03 24
2016-03-04 24
2016-03-05 24
2016-03-06 19
So far what I've tried:
SELECT
DATE_FORMAT(start_time,"%Y-%m-%d") `date`,
TIMESTAMPDIFF(HOUR,start_time,end_time) availableTime
FROM useractivity
GROUP BY `date`
Got output:
Date availableTime(Hours)
2016-02-28 9
2016-03-02 9
Here's the SQL FIDDLE
Note:
Please ignore the user_id for the time being. I can solve it in application level but I want to deal with it in MySQL.
The time interval can start one day and end more than one day later
In a word, the available time is just the projection in the day axis (from start time and end time). If the start time doesn't project into the same day as end time then the start time would be considered the start_time of that particular day where the end time projects into.
Pictorial View:
So available time will be calculated from this screenshot as follows:
28 Feb = (t2-t1) + (t4- t3)
29 Feb = (t5 - t4)
02 Mar = (t7 - t6)
You could use a date table to cross join to get the real start and end time in the day you want to split from the log time.
CREATE TABLE `dates` (
`date` date ,
`start_time` timestamp ,
`end_time` timestamp
);
INSERT INTO `dates` VALUES('20160228','2016-02-28 00:00:00', '2016-02-29 00:00:00');
INSERT INTO `dates` VALUES('20160229','2016-02-29 00:00:00', '2016-03-01 00:00:00');
INSERT INTO `dates` VALUES('20160301','2016-03-01 00:00:00', '2016-03-02 00:00:00');
INSERT INTO `dates` VALUES('20160302','2016-03-02 00:00:00', '2016-03-03 00:00:00');
INSERT INTO `dates` VALUES('20160303','2016-03-03 00:00:00', '2016-03-04 00:00:00');
INSERT INTO `dates` VALUES('20160304','2016-03-04 00:00:00', '2016-03-05 00:00:00');
INSERT INTO `dates` VALUES('20160305','2016-03-05 00:00:00', '2016-03-06 00:00:00');
INSERT INTO `dates` VALUES('20160306','2016-03-06 00:00:00', '2016-03-07 00:00:00');
SELECT
u.*,
d.date,
case when u.start_time<= d.start_time then d.start_time
else u.start_time end as `start_time_in_the_day`,
case when u.end_time> d.end_time then d.end_time
else u.end_time end as `end_time_in_the_day`
FROM useractivity u
INNER JOIN dates d
ON u.start_time< d.end_time
and u.end_time>= d.start_time
Then you just need to sum the hours between end_time_in_the_day and start_time_in_the_day.
SELECT
user_id,
date,
sum(TIMESTAMPDIFF(HOUR,start_time_in_the_day,end_time_in_the_day)) as `availableTime`
FROM(
SELECT
u.*,
d.date,
case when u.start_time<= d.start_time then d.start_time
else u.start_time end as `start_time_in_the_day`,
case when u.end_time> d.end_time then d.end_time
else u.end_time end as `end_time_in_the_day`
FROM useractivity u
INNER JOIN dates d
ON u.start_time< d.end_time
and u.end_time>= d.start_time) as t
group by user_id,date
My SqlFiddle here.
And I think use TIMESTAMPDIFF(SECOND... instead TIMESTAMPDIFF(HOUR... would be better.
I have created a query help of UNION ALL
SELECT sub_query.`date`, SUM(sub_query.available_time) FROM (
SELECT
DATE_FORMAT(start_time,"%Y-%m-%d") `date`,
IF(TIMESTAMPDIFF(day,date(start_time),date(end_time))= 0,
TIMESTAMPDIFF(HOUR,start_time,end_time),0) AS available_time
FROM useractivity
UNION ALL
SELECT
DATE_FORMAT(start_time,"%Y-%m-%d") `date`,
IF(TIMESTAMPDIFF(day,date(start_time),date(end_time)) > 0,
TIMESTAMPDIFF(HOUR,start_time, date_add(date(start_time),interval 24 hour)),0) AS available_time
FROM useractivity
UNION ALL
SELECT
DATE_FORMAT(end_time,"%Y-%m-%d") `date`,
IF(TIMESTAMPDIFF(day,date(start_time),date(end_time)) > 0,
TIMESTAMPDIFF(HOUR,date(end_time), end_time) , 0) AS available_time
FROM useractivity
) AS sub_query
GROUP BY sub_query.`date`
UNION
SELECT SELECTed_date `date`, 24 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 (SELECT min(date(start_time)) FROM useractivity) and (SELECT max(date(end_time)) FROM useractivity)
AND SELECTed_date NOT IN(
SELECT miss_date FROM (
SELECT date(start_time) AS miss_date FROM useractivity
UNION
SELECT date(end_time) AS miss_date FROM useractivity
) AS miss
) ORDER BY `date`;
SQLFiddle
I've modified #Vipin Jain's query to fulfill the requirement:
SELECT sub_query.`date`, SUM(sub_query.available_time) FROM (
SELECT
DATE_FORMAT(start_time,"%Y-%m-%d") `date`,
IF(TIMESTAMPDIFF(day,date(start_time),date(end_time))= 0,
TIMESTAMPDIFF(HOUR,start_time,end_time),0) AS available_time
FROM useractivity
UNION ALL
SELECT
DATE_FORMAT(start_time,"%Y-%m-%d") `date`,
IF(TIMESTAMPDIFF(day,date(start_time),date(end_time)) > 0,
TIMESTAMPDIFF(HOUR,start_time, date_add(date(start_time),interval 24 hour)),0) AS available_time
FROM useractivity
UNION ALL
SELECT
DATE_FORMAT(end_time,"%Y-%m-%d") `date`,
IF(TIMESTAMPDIFF(day,date(start_time),date(end_time)) > 0,
TIMESTAMPDIFF(HOUR,date(end_time), end_time) , 0) AS available_time
FROM useractivity
) AS sub_query
GROUP BY sub_query.`date`
UNION
SELECT SELECTed_date `date`, 24 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 (SELECT min(date(start_time)) FROM useractivity) and (SELECT max(date(end_time)) FROM useractivity)
AND SELECTed_date NOT IN(
SELECT miss_date FROM (
SELECT date(start_time) AS miss_date FROM useractivity
UNION
SELECT date(end_time) AS miss_date FROM useractivity
) AS miss
)
AND EXISTS (SELECT 1 FROM useractivity WHERE SELECTed_date BETWEEN start_time AND end_time)
ORDER BY `date`;
Related
My company policy is that we count the Saturdays before 15 dates as working days and after 15 days as company holiday kindly tell me the function to count working days of the month skip all Sundays and Saturdays before 15 date in Query
You can use below code to count the working days as per your requirement -
CREATE FUNCTION FN_CNT_Working_days(StartDate DATE,
EndDate DATE)
RETURNS INT
BEGIN
DECLARE WORKING_DAYS INT;
SELECT
(DATEDIFF(EndDate, DATE(CONCAT(YEAR(EndDate), '-', MONTH(EndDate), '-', 16))) + 1)
-(FLOOR(DATEDIFF(EndDate, DATE(CONCAT(YEAR(EndDate), '-', MONTH(EndDate), '-', 16)))/7) * 2)
-(CASE WHEN DAYNAME(DATE(CONCAT(YEAR(EndDate), '-', MONTH(EndDate), '-', 16))) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DAYNAME(EndDate) = 'Saturday' THEN 1 ELSE 0 END)
+
(DATEDIFF(DATE(CONCAT(YEAR(EndDate), '-', MONTH(EndDate), '-', 15)), StartDate) + 1)
-(FLOOR(DATEDIFF(DATE(CONCAT(YEAR(EndDate), '-', MONTH(EndDate), '-', 15)), StartDate)/7))
-(CASE WHEN DAYNAME(StartDate) = 'Sunday' THEN 1 ELSE 0 END)
INTO WORKING_DAYS;
RETURN (WORKING_DAYS);
END;
Here is the fiddle. Also you need to take care of holidays along with this code.
You can try either one method below or can use the query which was shared by #Ankit.
If you have a table like calendar it will be useful in many ways.
METHOD: 1
If you have a Calendar table you can run the below query,
SELECT
SUM(CASE WHEN WEEKDAY(cal.cal_date) <> 6 AND DAY(cal.cal_date) < 16 THEN 1
WHEN WEEKDAY(cal.cal_date) NOT IN (5, 6) AND DAY(cal.cal_date) > 15 THEN 1 END) AS 'working days'
FROM
calendar cal
WHERE
cal.cal_date BETWEEN '2019-10-01' AND '2019-10-31';
METHOD: 2
If creating a TABLE OR VIEW is restricted can generate a range of dates using the below query
SELECT
SUM(CASE WHEN WEEKDAY(cal.cal_date) <> 6 AND DAY(cal.cal_date) < 16 THEN 1
WHEN WEEKDAY(cal.cal_date) NOT IN (5, 6) AND DAY(cal.cal_date) > 15 THEN 1 END) AS 'working days'
FROM
(SELECT
('1970-01-01' + INTERVAL (((((`t4`.`t4` * 10000) + (`t3`.`t3` * 1000)) + (`t2`.`t2` * 100)) + (`t1`.`t1` * 10)) + `t0`.`t0`) DAY) AS `cal_date`
FROM
((((((SELECT 0 AS `t0`) UNION ALL SELECT 1 AS `1` UNION ALL SELECT 2 AS `2` UNION ALL SELECT 3 AS `3` UNION ALL SELECT 4 AS `4` UNION ALL SELECT 5 AS `5` UNION ALL SELECT 6 AS `6` UNION ALL SELECT 7 AS `7` UNION ALL SELECT 8 AS `8` UNION ALL SELECT 9 AS `9`) `t0`
JOIN (SELECT 0 AS `t1` UNION ALL SELECT 1 AS `1` UNION ALL SELECT 2 AS `2` UNION ALL SELECT 3 AS `3` UNION ALL SELECT 4 AS `4` UNION ALL SELECT 5 AS `5` UNION ALL SELECT 6 AS `6` UNION ALL SELECT 7 AS `7` UNION ALL SELECT 8 AS `8` UNION ALL SELECT 9 AS `9`) `t1`)
JOIN (SELECT 0 AS `t2` UNION ALL SELECT 1 AS `1` UNION ALL SELECT 2 AS `2` UNION ALL SELECT 3 AS `3` UNION ALL SELECT 4 AS `4` UNION ALL SELECT 5 AS `5` UNION ALL SELECT 6 AS `6` UNION ALL SELECT 7 AS `7` UNION ALL SELECT 8 AS `8` UNION ALL SELECT 9 AS `9`) `t2`)
JOIN (SELECT 0 AS `t3` UNION ALL SELECT 1 AS `1` UNION ALL SELECT 2 AS `2` UNION ALL SELECT 3 AS `3` UNION ALL SELECT 4 AS `4` UNION ALL SELECT 5 AS `5` UNION ALL SELECT 6 AS `6` UNION ALL SELECT 7 AS `7` UNION ALL SELECT 8 AS `8` UNION ALL SELECT 9 AS `9`) `t3`)
JOIN (SELECT 0 AS `t4` UNION ALL SELECT 1 AS `1` UNION ALL SELECT 2 AS `2` UNION ALL SELECT 3 AS `3` UNION ALL SELECT 4 AS `4` UNION ALL SELECT 5 AS `5` UNION ALL SELECT 6 AS `6` UNION ALL SELECT 7 AS `7` UNION ALL SELECT 8 AS `8` UNION ALL SELECT 9 AS `9`) `t4`)) AS cal
WHERE
cal.cal_date BETWEEN '2019-10-01' AND '2019-10-31';
Fiddle here
This works without calendar table and by month. And you only need to change the date value #curdt variable. It can be any dates within the month as long as its not less or more than the real calendar dates e.g '2019-07-00' or '2019-07-32' - this won't work.
#1 : Setting variable.
SET #curdt := '2019-07-01'; #only need to change the date here.
SET #startdate := LAST_DAY(#curdt-INTERVAL 1 MONTH)+INTERVAL 1 DAY;
SET #lastdate := LAST_DAY(#curdt);
#2 : Count workdays.
SELECT SUM(CASE WHEN DAY(dt) <= 15 AND WEEKDAY(dt)=6 THEN 0
WHEN DAY(dt) > 15 AND WEEKDAY(dt) IN (5,6) THEN 0
ELSE 1 END) AS Workdays
FROM
(SELECT dt
FROM (
#custom calendar
SELECT CONCAT_WS('-',curmy,CONCAT(n2,n1)) dt
FROM
(SELECT 0 AS n1 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 ) a CROSS JOIN
(SELECT 0 n2 UNION
SELECT 1 UNION
SELECT 2 UNION
SELECT 3) b CROSS JOIN
(SELECT LEFT(#curdt,7) curmy) c
) zz
WHERE dt BETWEEN #startdate AND #lastdate) XX
GROUP BY MONTH(dt);
Just tried a new query and might just add in here for future reference:
SET #curdate := CURDATE()-INTERVAL 1 MONTH;
SELECT * FROM
(SELECT CONCAT_WS('-',df,CONCAT(b,c)) dm FROM
(SELECT DATE_FORMAT(#curdate, '%Y-%m') df) a CROSS JOIN
(SELECT 0 b UNION SELECT 1 b UNION SELECT 2 UNION SELECT 3) b CROSS JOIN
(SELECT 0 c 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) c) d WHERE DAY(dm) BETWEEN 1 AND DAY(LAST_DAY(dm))
ORDER BY dm;
This method is for MariaDB - using it's sequence engine:
From MariaDB 10.1, the Sequence engine is installed by default.
SELECT DATE_FORMAT(CONCAT_WS('-',a.seq,b.seq,c.seq), '%Y-%m-%d') dates
FROM seq_2020_to_2021 a -- year range
CROSS JOIN seq_1_to_12 b -- month range
CROSS JOIN seq_1_to_31 c -- day range
HAVING dates IS NOT NULL; -- excluding invalid dates returned as NULL
I want to have a condition or return a result(1) when my query detects that I have a missing date and I'm calling it between two dates from the user.
As you can see I'm missing 3/22/2016 until 3/26/2016. I want to get a result from my query that there are missing dates in my query.
Can you give me hints on how to do this?
Here's my query:
select DISTINCT DOB from DATES where STR_TO_DATE(DOB, '%m/%d/%Y') BETWEEN '20160301' AND '20160331'
This will give only date is missing or not.
select case when count(DISTINCT DOB) = datediff('20160331','20160301') + 1 then 1 else 0 end
from DATES
where STR_TO_DATE(DOB, '%m/%d/%Y') BETWEEN '20160301' AND '20160331'
Below query will give you total dates present in it.
select asodate ,t1.dob
from
( SELECT #row := #row + interval 1 day as asofdate
FROM
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4,
(SELECT #row:='2016-03-01' - interval 1 day) a
where #row < '2016-03-31') generateCalender
left join
( select DISTINCT STR_TO_DATE(DOB, '%m/%d/%Y') as dob
from DATES
where STR_TO_DATE(DOB, '%m/%d/%Y') BETWEEN '20160301' AND '20160331' ) t1
on asofdate = t1.dob
You can easily find out all missing date by adding where condition.
where t1.dob is NULL
I have two tables user_profile and tracked_search. The user_profile table has user details and tracked_search tracks searches made by each user.
Whenever a user makes a search this search entry goes in the tracked_search table. If nothing is searched for a particular date nothing is added in tracked_search.
I need to develop a report where in I need to show on all days of month how many users made searches.
For example:
CREATE TABLE tracked_search (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
created DATE,
user_id int NOT NULL
);
INSERT INTO tracked_search(created, user_id) VALUES
('2017-10-01', 1000),
('2017-10-01', 1000),
('2017-10-01', 2000),
('2017-10-01', 3000),
('2017-10-01', 4000),
('2017-10-04', 1000),
('2017-10-04', 2000),
('2017-10-04', 2000),
('2017-10-04', 2000),
('2017-10-04', 2000),
('2017-10-04', 3000),
('2017-10-31', 1000),
('2017-10-31', 2000),
('2017-10-31', 3000),
('2017-10-31', 4000),
('2017-10-31', 5000);
Desired output:
Date user_count
2017-10-01 4
2017-10-02 0
2017-10-03 0
2017-10-04 3
2017-10-05 0
...
2017-10-30 0
2017-10-31 5
I have written following query
SELECT ts.created , count( distinct ts.user_id) FROM tracked_search ts, user_profile u
WHERE ts.created>=(CURDATE()-INTERVAL 1 MONTH) AND u.id = ts.user_id
group by ts.created;
but i get
Date user_count
2017-10-01 4
2017-10-04 3
2017-10-31 5
I need to print all days values if no entry is there for a particular date it should be zero.
I am using MySQL.
By the way, you don't need the join on user_profile.
If you have a dates table with the relevant dates, this is pretty easy:
SELECT dates.day AS `Date`, COUNT(DISTINCT ts.user_id) AS user_count
FROM dates
LEFT OUTER JOIN tracked_search AS ts
ON ts.created = dates.day
GROUP BY dates.day;
Since you probably don't have a dates table and might not want to create and maintain one, you could use one of the solutions for generating the list of dates on the fly. e.g. Get a list of dates between two dates or How to get list of dates between two dates in mysql select query
SELECT dates.day AS `Date`, COUNT(DISTINCT ts.user_id) AS user_count
FROM (
SELECT ADDDATE('1970-01-01', t4.i * 10000 + t3.i * 1000 + t2.i * 100 + t1.i * 10 + t0.i) AS day
FROM (SELECT 0 AS i 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 t0,
(SELECT 0 AS i 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 t1,
(SELECT 0 AS i 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 t2,
(SELECT 0 AS i 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 t3,
(SELECT 0 AS i 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 t4
) AS dates
LEFT OUTER JOIN tracked_search AS ts
ON ts.created = dates.day
WHERE dates.day >= '2017-10-01'
AND dates.day < '2017-11-01'
GROUP BY dates.day;
You need to write without AND u.id = ts.user_id.
SELECT ts.created , count( distinct ts.user_id) FROM tracked_search ts, user_profile u
WHERE ts.created>=(CURDATE()-INTERVAL 1 MONTH)
group by ts.created;
I was able to solve this using the following logic hope it will help someone
select
t1.attempt_date,
coalesce(SUM(t1.attempt_count+t2.attempt_count), 0) AS attempt_count
from
(
select DATE_FORMAT(a.Date,'%Y/%m/%d') as attempt_date,
'0' as attempt_count
from (
select curdate() - 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
where a.Date BETWEEN NOW() - INTERVAL 1 MONTH AND NOW()
)t1
left join
(
SELECT DATE_FORMAT(ts.created,'%Y/%m/%d') AS attempt_date,
count( distinct ts.user_id) AS attempt_count
FROM tracked_search ts, user_profile u
WHERE ts.user_id = u.id and
DATE_SUB(ts.created, INTERVAL 1 DAY) > DATE_SUB(DATE(NOW()), INTERVAL 1 MONTH)
GROUP BY DAY(ts.created) DESC
)t2
on t2.attempt_date = t1.attempt_date
group by DAY(t1.attempt_date)
order by t1.attempt_date desc;
I have a table of booking and need to find the count of booking in a specific date range in MYSQL. But it is giving me only non empty values. I need to show the non existence date within range as NULL in my select query. Here is my query:
SELECT DATE_FORMAT(booking_created_on, '%b %e') AS dateValue , COUNT(booking_id) AS cnt FROM booking WHERE booking_created_on BETWEEN '2016/02/01' AND '2016/02/08' GROUP BY booking_created_on
My result from this query is :
And my expected result is:
Please help me in mysql query for getting the desired result.
Try This
SELECT DATE_FORMAT(selected_date, '%b %e'), cnt
FROM(
SELECT
str_to_date(booking_created_on, '%Y/%m/%d') AS selected_date ,
COUNT(booking_id) AS cnt
FROM booking
WHERE booking_created_on BETWEEN '2016/02/01' AND '2016/02/08'
GROUP BY booking_created_on
UNION
SELECT selected_date,0 AS cnt 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 '2016-02-01' and '2016-02-08' AND selected_date NOT IN (
SELECT
DISTINCT(str_to_date(booking_created_on, '%Y/%m/%d')) FROM booking
WHERE booking_created_on BETWEEN '2016/02/01' AND '2016/02/08'
)
) AS T1
ORDER BY selected_date ;
In my query, first i get all date and count in your table and in second subquery i get all missing date which is not in your table between two dates. show result order by date. this is lengthy query so may be it will be some error so if any error, comment
I want to fill in the dates between today and 30 days ago in mysql.
eg:
Date Value
2015-08-05 1
2015-08-04 2
2015-08-03 0
......
2015-07-05 1
Below is mysql:
SELECT IFNULL(SUM(units.price), 0) as price, DATE(units.solddate) as date, DAY(units.solddate) as day,
(
select a.Date
from (
select curdate() - 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
where a.Date >= DATE_SUB(NOW(), INTERVAL 30 day)
) as onemonth
FROM (tables)
GROUP BY date
However, I got this error: #1242 - Subquery returns more than 1 row I understood this error.
Please advice. Thank you.
This is a solution by correcting your approach
SELECT
`dates`.`date` ,SUM( COALESCE( `units`.`price` ,0 ) ) AS `price`
FROM
(
-- Start of query for making dates
SELECT
`dates`.`date`
,CONCAT( `dates`.`date` ,' 00:00:00' ) AS `day_start_datetime`
,CONCAT( `dates`.`date` ,' 23:59:59' ) AS `day_end_datetime`
FROM
(
SELECT
DATE_SUB( CURDATE( ) ,INTERVAL `intervals`.`days` DAY ) AS `date`
FROM
(
SELECT
( `hundreds_place`.`num` * 100 )
+( `tens_place`.`num` * 10 )
+( `ones_place`.`num` * 1 ) AS `days`
FROM ( SELECT 0 AS `num` 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 ) AS `ones_place`
JOIN ( SELECT 0 AS `num` 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 ) AS `tens_place`
JOIN ( SELECT 0 AS `num` 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 ) AS `hundreds_place`
) `intervals`
HAVING
`date` >= DATE_SUB( CURDATE() ,INTERVAL 30 DAY )
) `dates`
-- End of query for making dates
) `dates`
LEFT OUTER JOIN `units`
ON `units`.`sold_date` BETWEEN `day_start_datetime` AND `day_end_datetime`
WHERE
1
GROUP BY
`dates`.`date`
ORDER BY
`dates`.`date`
After getting better understanding of what you are trying to achieve , I have put together this MySQL query .
I have tested it and it worked for me .
SELECT
`dates_table`.`date`
-- ,`dates_table`.`day`
,SUM( COALESCE( `units`.`price` ,0 ) ) AS `price`
FROM
-- Start of query for making dates_table
(
SELECT
DATE( DATE_SUB( CURDATE( ) ,INTERVAL `intervals_table`.`days` DAY ) ) AS `date`
,DAY( DATE_SUB( CURDATE( ) ,INTERVAL `intervals_table`.`days` DAY ) ) AS `day`
FROM
(
SELECT 0 AS `days`
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 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12
UNION SELECT 13 UNION SELECT 14 UNION SELECT 15 UNION SELECT 16
UNION SELECT 17 UNION SELECT 18 UNION SELECT 19 UNION SELECT 20
UNION SELECT 21 UNION SELECT 22 UNION SELECT 23 UNION SELECT 24
UNION SELECT 25 UNION SELECT 26 UNION SELECT 27 UNION SELECT 28
UNION SELECT 29 UNION SELECT 30 UNION SELECT 31
) `intervals_table`
HAVING
`date` >= DATE_SUB( CURDATE( ) ,INTERVAL 30 DAY )
)
-- End of query for making dates_table
`dates_table`
LEFT OUTER JOIN `units` ON
`units`.`sold_date` >= CONCAT( `dates_table`.`date` ,' 00:00:00' )
AND `units`.`sold_date` <= CONCAT( `dates_table`.`date` ,' 23:59:59' )
WHERE
1
GROUP BY
`dates_table`.`date`
ORDER BY
`dates_table`.`date`
The units table I have used for testing is :
CREATE TABLE IF NOT EXISTS `units` (
`id` int(11) NOT NULL AUTO_INCREMENT
,`price` int(11) NOT NULL
,`sold_date` datetime NOT NULL
,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `units` (`id`, `price`, `sold_date`) VALUES
(1, 10, '2015-08-02 00:00:00'),
(2, 11, '2015-08-03 00:00:00'),
(3, 14, '2015-08-03 00:00:00'),
(4, 3, '2015-08-04 00:00:00');
Result
date price
---------- -----
2015-07-07 0
2015-07-08 0
2015-07-09 0
2015-07-10 0
2015-07-11 0
2015-07-12 0
2015-07-13 0
2015-07-14 0
2015-07-15 0
2015-07-16 0
2015-07-17 0
2015-07-18 0
2015-07-19 0
2015-07-20 0
2015-07-21 0
2015-07-22 0
2015-07-23 0
2015-07-24 0
2015-07-25 0
2015-07-26 0
2015-07-27 0
2015-07-28 0
2015-07-29 0
2015-07-30 0
2015-07-31 0
2015-08-01 0
2015-08-02 10
2015-08-03 25
2015-08-04 3
2015-08-05 0