This question already has answers here:
generate days from date range
(30 answers)
Closed 3 years ago.
I have a following table with columns:
id | number | created_at
1 | A11 | 2020-01-01 06:08:19
2 | A21 | 2020-01-04 06:08:19
How do I query all the data in a date range from specific date and count all data per day?
I tried something like that :
SELECT DATE_FORMAT(created_at, '%Y-%m-%d') AS the_date , COUNT(*) AS count
FROM `transactions`
WHERE created_at BETWEEN DATE_FORMAT('2020-01-01', '%Y-%m-%d') AND DATE_FORMAT('2020-01-04', '%Y-%m-%d')
GROUP BY the_date
Then i got data like that :
the_date | count
2020-01-01 | 1
2020-01-04 | 1
I want to achieve
the_date | count
2020-01-01 | 1
2020-01-02 | 0
2020-01-03 | 0
2020-01-04 | 1
if your version is below mysql 8.0 then you can use this script :
step1 : create a sequence N rows table :
create table sequence(id int);
create procedure insert_data_proc(in v_i int)
begin
declare i int default 0;
while i < v_i
do
insert into sequence values (i);
set i = i + 1;
end while;
end;
call insert_data_proc(1000);
drop procedure insert_data_proc;
step2 : query the table and left join your table's by mindate,maxdate,datediff
select
t1.created_at the_date
,case when count is null then 0 else count end as count
from (
select date_add(t2.mincreated_at , interval id day) created_at
from sequence t1
left join (
select datediff(max(created_at),min(created_at)) diff
,date(min(created_at) ) mincreated_at
,date(max(created_at) ) maxcreated_at
from transactions
) t2 on 1=1
where t1.id < t2.diff+1
) t1
left join (
select date(created_at) created_at,count(1) count
from transactions
group by date(created_at)
) t2 on t1.created_at = t2.created_at
order by the_date
note : if your data's days over 1000 day then you only need to increase the SP value.
[Online Demo Link MySQL 5.7 | db<>fiddle](https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=57d3e60bb2b918e8b6d2d8f3d5e63a6c
)
you can use like this :
SET #date_min = '2019-01-01';
SET #date_max = '2019-01-04';
SELECT
date_generator.date as the_date,
IFNULL(COUNT(transactions.id), 0) as count
from (
select DATE_ADD(#date_min, INTERVAL (#i:=#i+1)-1 DAY) as `date`
from information_schema.columns,(SELECT #i:=0) gen_sub
where DATE_ADD(#date_min,INTERVAL #i DAY) BETWEEN #date_min AND #date_max
) date_generator
left join transactions on DATE(created_at) = date_generator.date
GROUP BY date;
so here I am creating a temporary table date_generator will dates in between of given date range and join to with your main table (transactions).
output as expected:
the_date | count
2020-01-01 | 1
2020-01-02 | 0
2020-01-03 | 0
2020-01-04 | 1
I will give a suggestion for you to do this,
1 Solution
Create temporary table and add the dates and then join with the transactions table
create temporary table tempcalander
as
select * from
(select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) dates 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 dates between '2020-01-01' and '2020-01-04';
SELECT DATE_FORMAT(dates, '%Y-%m-%d') AS the_date , COUNT(created_at) AS count
FROM transactions t right join tempcalander c on t.created_at = c.dates
WHERE dates BETWEEN DATE_FORMAT('2020-01-01', '%Y-%m-%d') AND DATE_FORMAT('2020-01-04', '%Y-%m-%d')
GROUP BY the_date
2 Solution
you can create a separate table to add your dates.
CREATE TABLE calendar
(
dates date PRIMARY KEY
) ;
Then add you dates to this table,
INSERT INTO
calendar (dates)
VALUES
('2020-01-01'),
('2020-01-02'),
('2020-01-03'),
('2020-01-04'),
('2020-01-05'),
('2020-01-06') ;
after you can join the the transactions table with the calendar table and get the output
SELECT DATE_FORMAT(dates, '%Y-%m-%d') AS the_date , COUNT(created_at) AS count
FROM transactions t right join calendar c on t.created_at = c.dates
WHERE dates BETWEEN DATE_FORMAT('2020-01-01', '%Y-%m-%d') AND DATE_FORMAT('2020-01-04', '%Y-%m-%d')
GROUP BY the_date
Related
This is my MySQL table:
ID start end
==== ===== ===
01 01/01/2020 10/01/2020
02 09/01/2020 31/01/2020
03 02/01/2020 04/01/2020
I'm trying to get unique list of days which overlapping with themself, so this is a expected result:
results
=====
02/01/2020
03/01/2020
04/01/2020
09/01/2020
10/01/2020
I tried to get this using "between", but it only returns a date range. This is my query:
SELECT t1.*
FROM $table AS t1, $table AS t2
WHERE t1.id > t2.id
AND (t1.check_in_date BETWEEN t2.check_in_date AND t2.check_in_date
OR t1.check_out_date BETWEEN t2.check_in_date AND t2.check_out_date
OR t1.check_in_date >= t2.check_in_date AND t1.check_out_date <= t2.check_out_date)
Can I expand this query to achive my goal or need I to find completly diffrent way?
UPDATE (copied from the comment)
I'm using MariaDB v.10.0.44
WITH RECURSIVE
cte AS ( SELECT MIN(`start`) `date`
FROM sourcetable
UNION ALL
SELECT `date` + INTERVAL 1 DAY
FROM cte
WHERE `date` < ( SELECT MAX(`end`)
FROM sourcetable )
)
SELECT cte.`date`
FROM cte
JOIN sourcetable src ON cte.`date` BETWEEN src.`start` AND src.`end`
GROUP BY cte.`date`
HAVING COUNT(*) > 1;
fiddle
In MySQL 5.x you may use the next technique:
SELECT cte.`date`
FROM ( SELECT min_date.min_start + INTERVAL n1.n*10+n2.n DAY `date`
FROM ( SELECT MIN(sourcetable.`start`) min_start
FROM sourcetable ) min_date,
( SELECT 0 n 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 ) n1,
( SELECT 0 n 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 ) n2
) cte
JOIN sourcetable src ON cte.`date` BETWEEN src.`start` AND src.`end`
GROUP BY cte.`date`
HAVING COUNT(*) > 1;
fiddle
Above query assumes that the difference between minimal and maximal date in a table is not more than 99 days. If it may be greater then more digits-generated subqueries must be added with proper expression edition.
I want to count the number of actions per day in my dataset.
date action_id
2010-01-01 id00
2010-01-03 id01
2010-01-05 id02
This is just a sample, but the point is that my data does not include actions for every day and I want to include days where there are zero actions in my result.
My plan is to do this.
with dates as (
select [sequence of dates from 2010-01-01 to 2010-02-01] as day)
select day, coalesce(count(distinct action_id), 0) as actions
from dates
left join my_table
on dates.date = my_table.date
How do I create the sequence of dates?
You example shows a CTE. So, you can use a recursive CTE:
with recursive dates as (
select date('2010-01-01') as day
union all
select day + interval 1 day
from dates
where day < '2010-02-01'
)
select d.day, count(distinct t.action_id) as actions
from dates d left join
my_table t
on d.day = my_table.date
group by d.day;
Note that COUNT() never returns NULL, so COALESCE() is unnecessary.
In older versions, you can use a calendar table or generate the data on the fly. Assuming your table has enough rows:
select d.day, count(distinct t.action_id) as actions
from (select date('2010-01-01') + interval (#rn := #rn + 1) - 1 day as day
from my_table cross join
(select #rn := 0) params
limit 31
) d left join
my_table t
on d.day = my_table.date
group by d.day;
it seems just you need group by and count
select date, count(distinct action_id) as action
from my_table left join
dates on dates.date = my_table.date
group by date
with dates as
(
select a.Date
from (
select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.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
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 d
) a
where a.Date between '<start_date>' and '<end_date>' )
select day, count(distinct action_id) as actions
from dates
left join my_table
on dates.date = my_table.date
I have a database of users. I would like to create a graph based on userbase growth. The query I have now is:
SELECT DATE(datecreated), count(*) AS number FROM users
WHERE DATE(datecreated) > '2009-06-21' AND DATE(datecreated) <= DATE(NOW())
GROUP BY DATE(datecreated) ORDER BY datecreated ASC
This returns almost what I want. If we get 0 users one day, that day is not returned as a 0 value, it is just skipped and the next day that has at least one user is returned. How can I get something like (psuedo-response):
date1 5
date2 8
date3 0
date4 0
date5 9
etc...
where the dates with zero show up in sequential order with the rest of the dates?
Thanks!
I hope you will figure out the rest.
select * from (
select date_add('2003-01-01 00:00:00.000', INTERVAL n5.num*10000+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) 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) 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) 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) n4,
(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) n5
) a
where date >'2011-01-02 00:00:00.000' and date < NOW()
order by date
With
select n3.num*100+n2.num*10+n1.num as date
you will get a column with numbers from 0 to max(n3)*100+max(n2)*10+max(n1)
Since here we have max n3 as 3, SELECT will return 399, plus 0 -> 400 records (dates in calendar).
You can tune your dynamic calendar by limiting it, for example, from min(date) you have to now().
This question asks the same thing I think. Generally the accepted answer seems to be that you either do it in your application logic (read in what you have into an array, then loop through the array and create the missing dates), or you use temporary tables filled with the dates you wish to join.
This is better to do as:
-- 7 Days:
set #n:=date(now() + interval 1 day);
SELECT qb.day_series as days , COALESCE(col_byte, 0) as Bytes from tbl1 qa
right join (
select (select #n:= #n - interval 1 day) day_series from tbl1 limit 7 ) as qb
on date(qa.Timestamp) = qb.day_series and
qa.Timestamp > DATE_SUB(curdate(), INTERVAL 7 day) order by qb.day_series asc
-- 30 Days:
set #n:=date(now() + interval 1 day);
SELECT qb.day_series as days , COALESCE(col_byte, 0) as Bytes from tbl1 qa
right join (
select (select #n:= #n - interval 1 day) day_series from tbl1 limit 30 ) as qb
on date(qa.Timestamp) = qb.day_series and
qa.Timestamp > DATE_SUB(curdate(), INTERVAL 30 day) order by qb.day_series asc;
or without variable like this:
SELECT qb.day_series as days , COALESCE(col_byte, 0) as Bytes from tbl1 qa
right join (
select curdate() - INTERVAL a.a day as day_series 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
) as a ) as qb
on date(qa.Timestamp) = qb.day_series and
qa.Timestamp > DATE_SUB(curdate(), INTERVAL 7 day) order by qb.day_series asc;
Do a right outer join to a table, call it tblCalendar, that is pre-populated with the dates you wish to report on. And join on the date field.
Paul
Query is:
SELECT qb.dy as yourday, COALESCE(count(yourcolumn), 0) as yourcount from yourtable qa
right join (
select curdate() as dy union
select DATE_SUB(curdate(), INTERVAL 1 day) as dy union
select DATE_SUB(curdate(), INTERVAL 2 day) as dy union
select DATE_SUB(curdate(), INTERVAL 3 day) as dy union
select DATE_SUB(curdate(), INTERVAL 4 day) as dy union
select DATE_SUB(curdate(), INTERVAL 5 day) as dy union
select DATE_SUB(curdate(), INTERVAL 6 day) as dy
) as qb
on qa.dates = qb.dy
and qa.dates > DATE_SUB(curdate(), INTERVAL 7 day)
order by qb.dy asc;
and the result is:
+------------+-----------+
| yourday | yourcount |
+------------+-----------+
| 2015-06-24 | 274339 |
| 2015-06-25 | 0 |
| 2015-06-26 | 0 |
| 2015-06-27 | 0 |
| 2015-06-28 | 134703 |
| 2015-06-29 | 87613 |
| 2015-06-30 | 0 |
+------------+-----------+
On further thought, something like this should be what you want:
CREATE TEMPORARY TABLE DateSummary1 ( datenew timestamp ) SELECT DISTINCT(DATE(datecreated)) as datenew FROM users;
CREATE TEMPORARY TABLE DateSummary2 ( datenew timestamp, number int ) SELECT DATE(datecreated) as datenew, count(*) AS number FROM users
WHERE DATE(datecreated) > '2009-06-21' AND DATE(datecreated) <= DATE(NOW())
GROUP BY DATE(datecreated) ORDER BY datecreated ASC;
SELECT ds1.datenew,ds2.number FROM DateSummary1 ds1 LEFT JOIN DateSummary2 ds2 on ds1.datenew=ds2.datenew;
This gives you all the dates in the first table, and the count summary data in the second table. You might need to replace ds2.number with IF(ISNULL(ds2.number),0,ds2.number) or something similar.
I'm calculating
the number of days a reservation took place over every month (for every month since the first record)
A total price based on the total # of days and rate.
INSERT INTO `reservations`
(`id`, `user_id`, `property_id`, `actual_check_in`,`actual_check_out`)
VALUES
(5148, 1, 2, '2014-01-01', '2014-01-10'),
(5149, 1, 2, '2014-02-03', '2014-02-10'),
(5151, 1, 2, '2014-02-02', '2014-02-15'),
(5153, 1, 2, '2014-03-05', '2014-03-10'),
(5153, 1, 2, '2014-02-20', '2014-03-30'),
SELECT
YEAR(month.d),
MONTHNAME(month.d),
r.property_id,
SUM(
DATEDIFF(LEAST(actual_check_out, LAST_DAY(month.d)), GREATEST(actual_check_in, month.d))
) AS days,
SUM(days*p.rate),
MIN(r.actual_check_in) as firstDate,
MAX(r.actual_check_out) as lastDate
FROM reservations as r
LEFT JOIN property as p on r.property_id=p.id
RIGHT JOIN (
select
DATE_FORMAT(m1, '%Y%m%d') as d
from
(
select
(firstDate - INTERVAL DAYOFMONTH(firstDate)-1 DAY)
+INTERVAL m MONTH as m1
from
(
select #rownum:=#rownum+1 as m from
(select 1 union select 2 union select 3 union select 4) t1,
(select 1 union select 2 union select 3 union select 4) t2,
(select 1 union select 2 union select 3 union select 4) t3,
(select 1 union select 2 union select 3 union select 4) t4,
(select #rownum:=-1) t0
) d1
) d2
where m1<=lastDate
order by m1
) AS month ON
actual_check_in <= LAST_DAY(month.d)
AND month.d <= actual_check_out
GROUP BY user_id, month.d
Troubles I'm having:
getting MySQL to accept a variable for firstDate & lastDate in the joined query
I want to sum the monthly number of days together, for reservations by the same user, for the same month. I'm trying to turn the proper parts into a subquery to calculate that but having trouble..
http://sqlfiddle.com/#!9/71e34/1
I would like to have the results like (if the property rate is 150/day):
DATE | USER | #Days | Total Rate
--------------------------------------
01/2014 | 1 | 9 | 1350
01/2014 | 2 | 0 | 0
02/2014 | 1 | 30 | 4500
02/2014 | 2 | 0 | 0
03/2014 | 1 | 35 | 5250
03/2014 | 2 | 0 | 0
04/2014 | 1 | 0 | 0
04/2014 | 2 | 0 | 0
* # days can be more than the # of days in a month because there might be multiple reservations existing during that month
UPDATE---- This almost solved the problem, but I'm having trouble in the second large select statement to actually calculate the prices properly. The query is only taking in to account the first property rate, and not selecting them as per the join statement. Any help?
select
r.user_id,
DATE_FORMAT(m1, '%b %Y') as date,
(SELECT
SUM(
DATEDIFF(LEAST(actual_check_out, LAST_DAY(m1)), GREATEST(actual_check_in, m1))
) AS numdays
FROM reservations
where actual_check_in <= LAST_DAY(m1)
AND m1 <= actual_check_out
AND user_id=r.user_id
GROUP BY m1) as days,
(SELECT
SUM(
DATEDIFF(LEAST(r.actual_check_out, LAST_DAY(m1)), GREATEST(r.actual_check_in, m1))
) *p.rate
FROM reservations as r
left join property as p
on r.property_id=p.id
where actual_check_in <= LAST_DAY(m1)
AND m1 <= actual_check_out
AND user_id=r.user_id
GROUP BY m1) as price
from (
select ('2015-01-01' - INTERVAL DAYOFMONTH('2015-01-01')-1 DAY) +INTERVAL m MONTH as m1 from (
select #rownum:=#rownum+1 as m from
(select 1 union select 2 union select 3 union select 4) t1,
(select 1 union select 2 union select 3 union select 4) t2,
(select 1 union select 2 union select 3 union select 4) t3,
(select 1 union select 2 union select 3 union select 4) t4,
(select #rownum:=-1) t0
) d1
) d2
cross join reservations as r
where m1<=CURDATE() group by user_id, m1 order by m1
http://sqlfiddle.com/#!9/36035/21
Still not sure of your request, but the query below may point you to right direction:
SELECT DATE_FORMAT(r.actual_check_in, '%m/%Y') AS mnth, r.user_id,
DATEDIFF(MAX(r.actual_check_out),MIN(r.actual_check_in)) AS days,
DATEDIFF(MAX(r.actual_check_out),MIN(r.actual_check_in))*p.rate AS totalRate
FROM reservations r
JOIN property p ON r.property_id=p.id
GROUP BY DATE_FORMAT(r.actual_check_in, '%m/%Y'), r.user_id;
This returns data like below:
mnth user_id days totalRate
------- ------- ------ -----------
01/2014 1 9 1350
02/2014 1 56 8400
03/2014 1 5 750
http://sqlfiddle.com/#!9/36035/36
select
r.user_id as userId,
DATE_FORMAT(m1, '%b %Y') as date,
(SELECT
SUM(
DATEDIFF(LEAST(actual_check_out, LAST_DAY(m1)), GREATEST(actual_check_in, m1))
) AS numdays
FROM reservations
where actual_check_in <= LAST_DAY(m1)
AND m1 <= actual_check_out
AND user_id=userId
GROUP BY m1) as days,
(SELECT
sum(DATEDIFF(LEAST(r.actual_check_out, LAST_DAY(m1)), GREATEST(r.actual_check_in, m1))*p.rate)
FROM reservations as r
left join property as p
on r.property_id=p.id
where r.actual_check_in <= LAST_DAY(m1)
AND m1 <= r.actual_check_out
AND r.user_id=userId
GROUP BY m1) as price
from (
select ('2015-01-01' - INTERVAL DAYOFMONTH('2015-01-01')-1 DAY) +INTERVAL m MONTH as m1 from (
select #rownum:=#rownum+1 as m from
(select 1 union select 2 union select 3 union select 4) t1,
(select 1 union select 2 union select 3 union select 4) t2,
(select 1 union select 2 union select 3 union select 4) t3,
(select 1 union select 2 union select 3 union select 4) t4,
(select #rownum:=-1) t0
) d1
) d2
cross join reservations as r
where m1<=CURDATE() group by user_id, m1 order by m1
I have a database of users. I would like to create a graph based on userbase growth. The query I have now is:
SELECT DATE(datecreated), count(*) AS number FROM users
WHERE DATE(datecreated) > '2009-06-21' AND DATE(datecreated) <= DATE(NOW())
GROUP BY DATE(datecreated) ORDER BY datecreated ASC
This returns almost what I want. If we get 0 users one day, that day is not returned as a 0 value, it is just skipped and the next day that has at least one user is returned. How can I get something like (psuedo-response):
date1 5
date2 8
date3 0
date4 0
date5 9
etc...
where the dates with zero show up in sequential order with the rest of the dates?
Thanks!
I hope you will figure out the rest.
select * from (
select date_add('2003-01-01 00:00:00.000', INTERVAL n5.num*10000+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) 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) 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) 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) n4,
(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) n5
) a
where date >'2011-01-02 00:00:00.000' and date < NOW()
order by date
With
select n3.num*100+n2.num*10+n1.num as date
you will get a column with numbers from 0 to max(n3)*100+max(n2)*10+max(n1)
Since here we have max n3 as 3, SELECT will return 399, plus 0 -> 400 records (dates in calendar).
You can tune your dynamic calendar by limiting it, for example, from min(date) you have to now().
This question asks the same thing I think. Generally the accepted answer seems to be that you either do it in your application logic (read in what you have into an array, then loop through the array and create the missing dates), or you use temporary tables filled with the dates you wish to join.
This is better to do as:
-- 7 Days:
set #n:=date(now() + interval 1 day);
SELECT qb.day_series as days , COALESCE(col_byte, 0) as Bytes from tbl1 qa
right join (
select (select #n:= #n - interval 1 day) day_series from tbl1 limit 7 ) as qb
on date(qa.Timestamp) = qb.day_series and
qa.Timestamp > DATE_SUB(curdate(), INTERVAL 7 day) order by qb.day_series asc
-- 30 Days:
set #n:=date(now() + interval 1 day);
SELECT qb.day_series as days , COALESCE(col_byte, 0) as Bytes from tbl1 qa
right join (
select (select #n:= #n - interval 1 day) day_series from tbl1 limit 30 ) as qb
on date(qa.Timestamp) = qb.day_series and
qa.Timestamp > DATE_SUB(curdate(), INTERVAL 30 day) order by qb.day_series asc;
or without variable like this:
SELECT qb.day_series as days , COALESCE(col_byte, 0) as Bytes from tbl1 qa
right join (
select curdate() - INTERVAL a.a day as day_series 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
) as a ) as qb
on date(qa.Timestamp) = qb.day_series and
qa.Timestamp > DATE_SUB(curdate(), INTERVAL 7 day) order by qb.day_series asc;
Do a right outer join to a table, call it tblCalendar, that is pre-populated with the dates you wish to report on. And join on the date field.
Paul
Query is:
SELECT qb.dy as yourday, COALESCE(count(yourcolumn), 0) as yourcount from yourtable qa
right join (
select curdate() as dy union
select DATE_SUB(curdate(), INTERVAL 1 day) as dy union
select DATE_SUB(curdate(), INTERVAL 2 day) as dy union
select DATE_SUB(curdate(), INTERVAL 3 day) as dy union
select DATE_SUB(curdate(), INTERVAL 4 day) as dy union
select DATE_SUB(curdate(), INTERVAL 5 day) as dy union
select DATE_SUB(curdate(), INTERVAL 6 day) as dy
) as qb
on qa.dates = qb.dy
and qa.dates > DATE_SUB(curdate(), INTERVAL 7 day)
order by qb.dy asc;
and the result is:
+------------+-----------+
| yourday | yourcount |
+------------+-----------+
| 2015-06-24 | 274339 |
| 2015-06-25 | 0 |
| 2015-06-26 | 0 |
| 2015-06-27 | 0 |
| 2015-06-28 | 134703 |
| 2015-06-29 | 87613 |
| 2015-06-30 | 0 |
+------------+-----------+
On further thought, something like this should be what you want:
CREATE TEMPORARY TABLE DateSummary1 ( datenew timestamp ) SELECT DISTINCT(DATE(datecreated)) as datenew FROM users;
CREATE TEMPORARY TABLE DateSummary2 ( datenew timestamp, number int ) SELECT DATE(datecreated) as datenew, count(*) AS number FROM users
WHERE DATE(datecreated) > '2009-06-21' AND DATE(datecreated) <= DATE(NOW())
GROUP BY DATE(datecreated) ORDER BY datecreated ASC;
SELECT ds1.datenew,ds2.number FROM DateSummary1 ds1 LEFT JOIN DateSummary2 ds2 on ds1.datenew=ds2.datenew;
This gives you all the dates in the first table, and the count summary data in the second table. You might need to replace ds2.number with IF(ISNULL(ds2.number),0,ds2.number) or something similar.