我有一个SQL查询,如下所述,它选择两个日期之间的数据。
SELECT date, total FROM db WHERE date >= '2016-03-14' AND date <= '2016-03-20';
我想输出一个“0”,其中没有各种日期的数据,例如:
查询范围= 2016-03-14
到2016-03-20
目前我的SQL会输出:
Date Total
2016-03-14 50
我想输出:
Date Total
2016-03-14 50
2016-03-15 0
2016-03-16 0
2016-03-17 0
2016-03-18 0
2016-03-19 0
2016-03-20 0
如果没有复杂的连接,有没有办法做到这一点?
谢谢,
马特
答案 0 :(得分:1)
为数据中不存在的日期创建记录的最佳方法是加入日历表。
SELECT a.cal_dt, COALESCE(b.total,0) AS total
FROM lkp_Calendar a
LEFT JOIN db b
ON b.date = a.cal_dt
WHERE a.cal_dt >= '2016-03-14'
AND a.cal_dt <= '2016-03-20';
有很多好的脚本可以创建健壮的日历表,简单的就是:
CREATE TABLE lkp_Calendar (cal_dt date);
CREATE PROCEDURE addDates(dateStart DATE, dateEnd DATE)
BEGIN
WHILE dateStart <= dateEnd DO
INSERT INTO lkp_Calendar (cal_dt) VALUES (dateStart);
SET dateStart = date_add(dateStart, INTERVAL 1 DAY);
END WHILE;
END;
CALL addDates('2016-01-01','2016-12-31');
答案 1 :(得分:0)
SELECT date, COUNT(*) AS total FROM db WHERE date >= '2016-03-14' AND date <= '2016-03-20' GROUP BY date;
我假设:
日期只是一个日期(没有时间部分)
总不是一列,只是一个寄存器计数
答案 2 :(得分:0)
它不需要复杂的连接。但它确实需要一个行源来处理您想要返回的date
个值。
一种选择是使用填充了日期的calendar
表。
create table cal (dt DATE NOT NULL PRIMARY KEY) ... ;
insert into cal (dt) values ('2016-03-01');
insert into cal (dt) select dt + interval 1 day from cal order by dt;
insert into cal (dt) select dt + interval 2 day from cal order by dt;
insert into cal (dt) select dt + interval 4 day from cal order by dt;
insert into cal (dt) select dt + interval 8 day from cal order by dt;
insert into cal (dt) select dt + interval 16 day from cal order by dt;
然后从中抽出日期:
SELECT c.dt
FROM cal c
WHERE c.dt >= '2016-03-14'
AND c.dt < '2016-03-21'
然后只需对表进行简单的外连接:
SELECT c.dt AS `date`
, IFNULL(d.total,0) AS `total`
FROM cal c
LEFT
JOIN db d
ON d.date = c.dt
WHERE c.dt >= '2016-03-14'
AND c.dt < '2016-03-21'
ORDER BY c.dt
如果您没有日历表,则可以使用UNION ALL
的内联视图 SELECT c.dt AS `date`
, IFNULL(d.total,0) AS `total`
FROM ( SELECT '2016-03-14' + INTERVAL 0 DAY AS dt
UNION ALL SELECT '2016-03-15' + INTERVAL 0 DAY
UNION ALL SELECT '2016-03-16' + INTERVAL 0 DAY
UNION ALL SELECT '2016-03-17' + INTERVAL 0 DAY
UNION ALL SELECT '2016-03-18' + INTERVAL 0 DAY
UNION ALL SELECT '2016-03-19' + INTERVAL 0 DAY
UNION ALL SELECT '2016-03-20' + INTERVAL 0 DAY
) c
LEFT
JOIN db d
ON d.date = c.dt
ORDER BY c.dt
答案 3 :(得分:0)
您也可以尝试以下查询。这适用于您没有基础表中所有日期的记录的情况。
DECLARE @temp TABLE (dbdate DATE, total INT)
DECLARE @StartDate DATE = '2016-03-14'
DECLARE @EndDate DATE = '2016-03-20'
WHILE (@StartDate <= @EndDate)
BEGIN
INSERT @temp
SELECT @StartDate AS [dbDate], ISNULL((SELECT total FROM db WHERE [date] = @StartDate),0) AS Total
SET @StartDate = DATEADD(dd,1,@StartDate)
END
SELECT * FROM @temp
答案 4 :(得分:0)
试试这个(小提琴演示略有不同,因为我没有db
表的数据)
的 SQLFiddle Demo
强>
select selected_date,coalesce(count1,0) as count1 from
(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 '2016-03-14' and '2016-03-20'
) t
left join
(SELECT dt, count1 FROM db WHERE dt between '2016-03-14' and '2016-03-20') t1
on t.selected_date=t1.dt