使用0 - sql查询填充缺少的值

时间:2016-03-15 04:33:40

标签: mysql sql

我有一个SQL查询,如下所述,它选择两个日期之间的数据。

SELECT date, total FROM db WHERE date >= '2016-03-14' AND date <= '2016-03-20';

我想输出一个“0”,其中没有各种日期的数据,例如:

查询范围= 2016-03-142016-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

如果没有复杂的连接,有没有办法做到这一点?

谢谢,

马特

5 个答案:

答案 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