I have a table recording the start time and end time of events of interest:
CREATE TABLE event_log (start_time DATETIME, end_time DATETIME);
INSERT INTO event_log VALUES ("2013-06-03 09:00:00","2013-06-03 09:00:05"), ("2013-06-03 09:00:03","2013-06-03 09:00:07"), ("2013-06-03 09:00:10","2013-06-03 09:00:12");
+---------------------+---------------------+
| start_time | end_time |
+---------------------+---------------------+
| 2013-06-03 09:00:00 | 2013-06-03 09:00:05 |
| 2013-06-03 09:00:03 | 2013-06-03 09:00:07 |
| 2013-06-03 09:00:10 | 2013-06-03 09:00:12 |
+---------------------+---------------------+
I am looking for a way to create a "time series" table where one column is a time index and another column is the count of events in progress at that time. I can do it with a subquery and a generator:
SET #first_time := (SELECT MIN(start_time) FROM event_log);
SET #last_time := (SELECT MAX(end_time) FROM event_log);
CREATE OR REPLACE VIEW generator_16
AS SELECT 0 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 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL
SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL
SELECT 15;
CREATE TABLE time_series (t DATETIME, event_count INT(11))
SELECT #first_time + INTERVAL n SECOND t, NULL AS event_count
FROM generator_16
WHERE #first_time + INTERVAL n SECOND <= #last_time;
UPDATE time_series
SET event_count= (SELECT COUNT(*) FROM event_log
WHERE start_time<=t AND end_time>=t);
+---------------------+-------------+
| t | event_count |
+---------------------+-------------+
| 2013-06-03 09:00:00 | 1 |
| 2013-06-03 09:00:01 | 1 |
| 2013-06-03 09:00:02 | 1 |
| 2013-06-03 09:00:03 | 2 |
| 2013-06-03 09:00:04 | 2 |
| 2013-06-03 09:00:05 | 2 |
| 2013-06-03 09:00:06 | 1 |
| 2013-06-03 09:00:07 | 1 |
| 2013-06-03 09:00:08 | 0 |
| 2013-06-03 09:00:09 | 0 |
| 2013-06-03 09:00:10 | 1 |
| 2013-06-03 09:00:11 | 1 |
| 2013-06-03 09:00:12 | 1 |
+---------------------+-------------+
Is there a more efficient way to do it? This method requires a subquery for every time index. Would there, for example, be a way to do it that requires one subquery per "event_log" record? My real problem has 500k time index entries and 1k events; it's taking a little longer than I would like (about 90 seconds).
The "generator" snippet came from http://use-the-index-luke.com/blog/2011-07-30/mysql-row-generator . Clearly one of the larger generators, like the 64k version or the 1M version, would be needed for larger problems.
The only changes happen at start_time and end_time.
So, if you were to
select distinct start_time As time_point from event_log
UNION
select distinct end_time As time_point from event_log
... that would give you all the "points" at which you need a snapshot.
If you create that in a temporary table (say TEMP_POINTS), and join if back to event_log, you should be able to count the number of events at each "point".
CREATE TABLE NON_ZERO_POINTS (t DATETIME, event_count INT(11))
select time_point, count(*)
from TEMP_POINTS
join event_log on time_point between start_time and end_time
group by time_point
Might be worth creating an index on NON_ZERO_POINTS
Then, you could use NON_ZERO_POINTS in your update thus:
UPDATE time_series
SET event_count= (SELECT event_count FROM NON_ZERO_POINTS
WHERE t=time_point);
Also, do you need to update time_series? If not, you could just use it in a query:
select t, coalesce(event_count)
from time_series
left join FROM NON_ZERO_POINTS
on t=time_point
Related
Given this query...
select
sum(count) as quotes,
date
from (
select
1 as count,
DATE_FORMAT(CONVERT_TZ(createdAt, 'UTC', 'US/Pacific'), "%Y-%m-%d") as date
from quotes
where deletedAt IS NULL
) q1
group by date
order by date;
I get the following results (showing 2020-02 results only, but actual results would go back several years)...
NOTE: 2020-02-02 received 0 quotes and is missing
+-------+------------+
| count | date |
+-------+------------+
| 1 | 2020-02-01 |
| 2 | 2020-02-03 |
| 1 | 2020-02-04 |
| 1 | 2020-02-05 |
| 1 | 2020-02-06 |
| 1 | 2020-02-07 |
| 3 | 2020-02-08 |
| 3 | 2020-02-09 |
| 3 | 2020-02-10 |
| 1 | 2020-02-11 |
+-------+------------+
How do I modify the query to...
Fill in the missing days (e.g. 2020-02-02 in this example)
add the ytdCount column, which is a rolling count by year
so that the output is like this...
add the ytdCount column
\/
+-------+----------+------------+
| count | ytdCount | date |
+-------+----------+------------+
| 1 | 1 | 2020-02-01 |
| 0 | 1 | 2020-02-02 | <- was missing from previous example
| 2 | 3 | 2020-02-03 |
| 1 | 4 | 2020-02-04 |
| 1 | 5 | 2020-02-05 |
| 1 | 6 | 2020-02-06 |
| 1 | 7 | 2020-02-07 |
| 3 | 10 | 2020-02-08 |
| 3 | 13 | 2020-02-09 |
| 3 | 16 | 2020-02-10 |
| 1 | 17 | 2020-02-11 |
+-------+----------+------------+
References
I found MYSQL to calculate YTD which shows how to do this if I were selecting from a simple table, but since my "table" is actually a select statement, I'm not sure how to translate the example to my use case.
I found get all dates in the current month which shows how to generate all the dates in a month, but I need all the days for a particular year.
I solved the problem by creating two temporary tables and a UNION
Create temp table for quotes
DROP TABLE IF EXISTS __quotes__;
CREATE TABLE __quotes__ (quotes INT(11), ytdQuotes INT(11), date DATE)
ENGINE=MEMORY
AS
select
sum(count) as quotes,
NULL as ytdQuotes,
date
from (select 1 as count, DATE_FORMAT(CONVERT_TZ(createdAt, 'UTC', 'US/Pacific'), "%Y-%m-%d") as date from quotes where deletedAt IS NULL) q1 group by date order by date;
Create temp table for the date range
note: you can easily get more/less days by changing the wear clause
DROP TABLE IF EXISTS __daterange__;
CREATE TABLE __daterange__ (quotes INT(11), ytdQuotes INT(11), date DATE)
ENGINE=MEMORY
AS
select
NULL as quotes,
NULL as ytdQuotes
date
from (select date
from (
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
) daterange
where date >= "2012-11-14") daterange;
Finally, here's the query that brings it all together
select
coalesce(sum(quotes), 0) as quotes,
coalesce((select sum(q2.quotes) from __quotes__ q2 where YEAR(report.date) = YEAR(q2.date) AND q2.date <= report.date), 0) as ytdQuotes,
date
from (
select * from __quotes__
UNION ALL
select * from __daterange__
) report
group by date
I have a table with 'ON' and 'OFF' values in column activity and another column datetime.
id(AUTOINCREMENT) id_device activity datetime
1 a ON 2017-05-26 22:00:00
2 b ON 2017-05-26 05:00:00
3 a OFF 2017-05-27 04:00:00
4 b OFF 2017-05-26 08:00:00
5 a ON 2017-05-28 12:00:00
6 a OFF 2017-05-28 15:00:00
I need to get total ON time by day
day id_device total_minutes_on
2017-05-26 a 120
2017-05-26 b 180
2017-05-27 a 240
2017-05-27 b 0
2017-05-28 a 180
2017-05-28 b 0
i have searched and tried answers for another posts, i tried TimeDifference and i get correct total time.
I don't find the way to get total time grouped by date
i appreciate your help
I'm not posting this as a definite answer rather it's an experiment for me and hopefully you'll find is useful in your case. Also I would like to mention that the MySQL database version I'm working with is quite old so the method I'm using is also very manual to say the least.
First of all lets extract your expected output:
The date value in day need to be repeated twice fro each of id_device a and b.
Minutes are calculated based on the activity; if activity is 'ON' until tomorrow, it needs to be calculated until the day end at 24:00:00 while the next day will calculate minutes until the activity is OFF.
What I come up with is this:
Creating condition (1):
SELECT * FROM
(SELECT DATE(datetime) dtt FROM mytable GROUP BY DATE(datetime)) a,
(SELECT id_device FROM mytable GROUP BY id_device) b
ORDER BY dtt,id_device;
The query above will return the following result:
+------------+-----------+
| dtt | id_device |
+------------+-----------+
| 2017-05-26 | a |
| 2017-05-26 | b |
| 2017-05-27 | a |
| 2017-05-27 | b |
| 2017-05-28 | a |
| 2017-05-28 | b |
+------------+-----------+
*Above will only work with all the dates you have in the table. If you want all date regardless if there's activity or not, I suggest you create a calendar table (refer: Generating a series of dates).
So this become the base query. Then I've added an outer query to left join the query above with the original data table:
SELECT v.*,
GROUP_CONCAT(w.activity ORDER BY w.datetime SEPARATOR ' ') activity,
GROUP_CONCAT(TIME_TO_SEC(TIME(w.datetime)) ORDER BY w.datetime SEPARATOR ' ') tr
FROM
-- this was the first query
(SELECT * FROM
(SELECT DATE(datetime) dtt FROM mytable GROUP BY DATE(datetime)) a,
(SELECT id_device FROM mytable GROUP BY id_device) b
ORDER BY a.dtt,b.id_device) v
--
LEFT JOIN
mytable w
ON v.dtt=DATE(w.datetime) AND v.id_device=w.id_device
GROUP BY DATE(v.dtt),v.id_device
What's new in the query is the addition of GROUP_CONCAT operation on both activity and time value extracted from datetime column which is converted into seconds value. You notice that in both of the GROUP_CONCAT there's a similar ORDER BY condition which is important in order to get the exact corresponding value.
The query above will return the following result:
+------------+-----------+----------+-------------+
| dtt | id_device | activity | tr |
+------------+-----------+----------+-------------+
| 2017-05-26 | a | ON | 79200 |
| 2017-05-26 | b | ON OFF | 18000 28800 |
| 2017-05-27 | a | OFF | 14400 |
| 2017-05-27 | b | (NULL) | (NULL) |
| 2017-05-28 | a | ON OFF | 43200 54000 |
| 2017-05-28 | b | (NULL) | (NULL) |
+------------+-----------+----------+-------------+
From here, I've added another query outside to calculate how many minutes and attempt to get the expected result:
SELECT dtt,id_device,
CASE
WHEN SUBSTRING_INDEX(activity,' ',1)='ON' AND SUBSTRING_INDEX(activity,' ',-1)='OFF'
THEN (SUBSTRING_INDEX(tr,' ',-1)-SUBSTRING_INDEX(tr,' ',1))/60
WHEN activity='ON' THEN 1440-(tr/60)
WHEN activity='OFF' THEN tr/60
WHEN activity IS NULL AND tr IS NULL THEN 0
END AS 'total_minutes_on'
FROM
-- from the last query
(SELECT v.*,
GROUP_CONCAT(w.activity ORDER BY w.datetime SEPARATOR ' ') activity,
GROUP_CONCAT(TIME_TO_SEC(TIME(w.datetime)) ORDER BY w.datetime SEPARATOR ' ') tr
FROM
-- this was the first query
(SELECT * FROM
(SELECT DATE(datetime) dtt FROM mytable GROUP BY DATE(datetime)) a,
(SELECT id_device FROM mytable GROUP BY id_device) b
ORDER BY a.dtt,b.id_device) v
--
LEFT JOIN
mytable w
ON v.dtt=DATE(w.datetime) AND v.id_device=w.id_device
GROUP BY DATE(v.dtt),v.id_device
--
) z
The last part I do is if the activity value have both ON and OFF on the same day then (OFF-ON)/60secs=total minutes. If activity value is only ON then minutes value for '24:00:00' > 24 hr*60 min= 1440-(ON/60secs)= total minutes, and if activity only OFF, I just convert seconds to minutes because the day starts at 00:00:00 anyhow.
+------------+-----------+------------------+
| dtt | id_device | total_minutes_on |
+------------+-----------+------------------+
| 2017-05-26 | a | 120 |
| 2017-05-26 | b | 180 |
| 2017-05-27 | a | 240 |
| 2017-05-27 | b | 0 |
| 2017-05-28 | a | 180 |
| 2017-05-28 | b | 0 |
+------------+-----------+------------------+
Hopefully this will give you some ideas. ;)
How can I make an sql query return a row for every day in a range of dates in mysql?
I have a job table that has this kind of structure:
job_id | station_id | start_date | end_date |
--------+---------------+---------------+---------------+
1 | 1 | 2017-06-01 | 2017-06-02 |
2 | 2 | 2017-06-01 | 2017-06-03 |
3 | 1 | 2017-06-02 | 2017-06-04 |
4 | 4 | 2017-06-01 | 2017-06-02 |
5 | 2 | 2017-06-04 | 2017-06-05 |
6 | 1 | 2017-06-06 | 2017-06-08 |
7 | 3 | 2017-06-01 | 2017-06-02 |
and a station table:
station_id | type |
-----------+------------|
1 | 1 |
2 | 1 |
3 | 2 |
4 | 2 |
5 | 2 |
If I want to know something like how many station of type 2 were in use on 2017-06-01 I can easily do this:
SELECT COUNT(job_id)
FROM jobs
WHERE start_date <= '2017-06-01'
AND end_date > '2017-06-01'
AND station_id IN (SELECT station_id FROM station WHERE type = 2);
This example would tell us that 2 stations (3 and 4) were in use:
+-------------+
|COUNT(job_id)|
+-------------+
| 2 |
+-------------+
However, I would like this to return a row for every day in a range of dates.
So far I've solved this with a python script that runs the first query multiple times, is there a way to do this directly with mysql?
EDIT: As requested by user1960808 the expected result for range 2017-06-01 2017-06-03 and type 2 would be this:
+-----------+-------------+
| date |COUNT(job_id)|
+-----------+-------------+
|2017-06-01 | 2 |
|2017-06-02 | 0 |
|2017-06-03 | 0 |
+-----------+-------------+
Perhaps the simplest way is to generate the range:
select d.dte, count(job_id)
from (select '2017-06-01' as dte union all
select '2017-06-02' as dte
) d left join
jobs j
on j.start_date <= d.dte and j.end_date > d.dte
where j.station_id in (select station_id from station s where s.type = 2)
group by d.dte;
If you have lots of dates, this is not the most efficient solution.
If you can create an integer table as mentioned in below url then I think it can be achieved with below query.
https://www.xaprb.com/blog/2005/12/07/the-integers-table/
Query after creating an integer table
SELECT job_id,station_id,start_date + INTERVAL i DAY, start_date,end_date
FROM job
INNER JOIN integers
ON i <= DATEDIFF(end_date,start_date)
AND station_id IN (SELECT station_id FROM station WHERE type = 2);
Check this
DELIMITER $$
Create Procedure GetJobRunningCount(dStartDate datetime,dEndDate datetime,dType int)
Begin
DROP TABLE IF EXISTS CountSummary;
CREATE TEMPORARY TABLE CountSummary(SelectedDate date,Count int);
While (dStartDate<=dEndDate) do
insert into CountSummary(SelectedDate,Count)
SELECT dStartDate,COUNT(1)
FROM jobs jo
inner join station st on(st.station_id=jo.station_id and type=dType )
WHERE start_date <= dStartDate
AND end_date > dStartDate;
set dStartDate=Date_add(dStartDate,interval 1 Day);
End while;
select * from CountSummary;
END$$
DELIMITER ;
call GetJobRunningCount('2017-06-01','2017-06-08',2)
ID Timestamp Value
1 11:59.54 10
1 12.04.00 20
1 12.12.00 31
1 12.16.00 10
1 12.48.00 05
I want the result set as
ID Timestamp Value
1 11:59.54 10
1 12:00:00 10
1 12.04.00 20
1 12.12.00 31
1 12:15:00 31
1 12:16.00 10
1 12:30:00 10
1 12:45:00 10
1 12.48.00 05
More coffee will probably lead to a simpler solution, but consider the the following...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,timestamp TIMESTAMP
,value INT NOT NULL
);
INSERT INTO my_table VALUES
(1 ,'11:59:54',10),
(2 ,'12:04:00',20),
(3 ,'12:12:00',31),
(4 ,'12:16:00',10),
(5 ,'12:48:00',05);
... in addition, I have a table of integers, that looks like this:
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
So...
SELECT a.timestamp
, b.value
FROM
( SELECT x.*
, MIN(y.timestamp) min_timestamp
FROM
( SELECT timestamp
FROM my_table
UNION
SELECT SEC_TO_TIME((i2.i*10+i1.i)*900)
FROM ints i1
, ints i2
WHERE SEC_TO_TIME((i2.i*10+i1.i)*900)
BETWEEN (SELECT MIN(timestamp) FROM my_table)
AND (SELECT MAX(timestamp) FROM my_table)
ORDER
BY timestamp
) x
LEFT
JOIN my_table y
ON y.timestamp >= x.timestamp
GROUP
BY x.timestamp
) a
JOIN my_table b
ON b.timestamp = min_timestamp;
+-----------+-------+
| timestamp | value |
+-----------+-------+
| 11:59:54 | 10 |
| 12:00:00 | 20 |
| 12:04:00 | 20 |
| 12:12:00 | 31 |
| 12:15:00 | 10 |
| 12:16:00 | 10 |
| 12:30:00 | 5 |
| 12:45:00 | 5 |
| 12:48:00 | 5 |
+-----------+-------+
The idea is as follows. Use SERIES_GENERATE() to generate the missing time stamps with the 15 minute intervals and and union it with the existing data your table T. Now you would want to use LAST_VALUE with IGNORE NULLS. IGNORE NULLS is not implemented in HANA, therefore you have to do a bit of a workaround. I use COUNT() as a window function to count the non null values. I do the same on the original data and then join both on the count. This way I repeat the last non-null value.
select X.ID, X.TIME, Y.VALUE from (
select ID, TIME, value,
count(VALUE) over (order by TIME rows between unbounded preceding and current row) as CNT
from (
--add the missing 15 minute interval timestamps
select 1 as ID, GENERATED_PERIOD_START as TIME, NULL as VALUE
from SERIES_GENERATE_TIME('INTERVAL 15 MINUTE', '12:00:00', '13:00:00')
union all
select ID, TIME, VALUE from T
)
) as X join (
select ID, TIME, value,
count(value) over (order by TIME rows between unbounded preceding and current row) as CNT
from T
) as Y on X.CNT = Y.CNT
I have a table that stores the amount of errors according to what alarm-id it is. The table looks something like this:
|----DATE----|---ALARM_ID---|---COUNTER---|
| 2012-01-01 | 1 | 32 |
| 2012-01-01 | 2 | 28 |
| 2012-01-02 | 1 | 12 |
| 2012-01-02 | 2 | 23 |
| 2012-01-03 | 1 | 3 |
| 2012-01-03 | 2 | 9 |
| 2012-01-05 | 1 | 8 |
| 2012-01-05 | 2 | 1 |
| 2012-01-07 | 1 | 102 |
| 2012-01-07 | 2 | 78 |
Notice the gap between date (2012-01-03 - 2012-01-05) and (2012-01-05 - 2012-01-07). On these dates there isn't any data because the system, that my program is monitoring, haven't reported any errors at that date. What I'm looking for is a SQL SELECT query that returns the total amount of errors on each date, for example:
|----DATE----|---COUNTER---|
| 2012-01-01 | 60 |
| 2012-01-02 | 35 |
| 2012-01-03 | 12 |
| 2012-01-04 | 0 |
| 2012-01-05 | 9 |
| 2012-01-06 | 0 |
| 2012-01-07 | 180 |
I have a query that returns ID's even if they doesn't exist in the table, and if the ID doesn't exist, return the ID anyway with the COUNTER value 0. As such:
BEFORE AFTER
|---ID---|---COUNTER---| |---ID---|---COUNTER---|
| 1 | 2 | | 1 | 2 |
| 2 | 6 | | 2 | 6 |
| 3 | 1 | --> | 3 | 1 |
| 5 | 9 | | 4 | 0 |
| 6 | 10 | | 5 | 9 |
| 6 | 10 |
| 7 | 0 |
| 8 | 0 |
The query goes like this:
select t.num as ID, coalesce(yt.COUNTER, 0)
from all_stats yt right join
( select t1.num + t2.num * 10 + t3.num * 100 + t4.num * 1000 as num
from ( select 1 as num 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 0 ) t1 cross join
( select 1 as num 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 0 ) t2 cross join
( select 1 as num 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 0 ) t3 cross join
( select 1 as num 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 0 ) t4 )
t on yt.ID = t.num
where (t.num between (select min(ID) from all_stats) and (select max(ID) from all_stats)) order by ID
I can't figure out how I can change this query when it's regarding dates. Can someone please help me on this issue?
I'm using MySQL
Thanks in advance, Steve-O
The exact details will depend on the DBMS, and on the nature of the database (e.g., OLAP-oriented vs. OLTP-oriented), but one common general approach is to create an auxiliary calendar table that represents dates as a dimension. Then you can use regular JOINs, rather than having to use complex logic to generate missing dates.
The answers to this StackOverflow question describe how to apply this approach on MySQL.
You can use a similar approach for numbers, by the way, by having a numbers tables; I've never done that myself for numbers, but it seems to be a popular idea; see this dba.stackexchange.com question.
If you're using SQL Server 2005 or above you can use a CTE (if not, a loop or other sql technique to populate a table with the dates in the range). Note also there is a limit to the levels of recursion within a CTE.
declare #dateRange table
(
dateBegin datetime,
dateEnd datetime
)
insert into #dateRange (dateBegin, dateEnd)
values ('2012-01-01', '2012-01-07')
;with cte (d)
as (select dateBegin as d
from #dateRange tbl
where datediff(day, tbl.dateBegin, tbl.dateEnd) <= 100
union all
select dateadd(day, 1, cte.d) as d
from cte
inner join #dateRange tbl on cte.d < tbl.dateEnd)
Then get the full results either using the CTE or a temporary table that contains the set of dates in the range:
select cte.d, sum(isnull(e.errorCounter, 0))
from cte
left outer join #errors e on e.errorDate = cte.d
group by cte.d
order by cte.d
You really should handle this at the application layer (ie iterate over the known date range and pull the non-zero vals from the resultset) or fix your table to always include the dates needed if you MUST have a database-centered solution. There's no really good way to generate, on the fly, a set of dates to use in building a continuous date range query.
You can see this for some examples of DB scripting solutions:
Return temp table of continuous dates
But I think you're posing the wrong question. Fix the database to include what you need, or fix how you're generating your report. Databases aren't meant to do interpolation and data generation.