如何在数据库中显示没有任何记录的 0 行

use*_*060 3 mysql

我的数据库中有很多记录,为了数据分析,我需要显示每天的记录数,包括我没有任何记录的日子,所以结果是0.

例如我有这些记录(SQL Fiddle):

CREATE TABLE Tabs
    (`timestamp` varchar(10), `id` int)
;

INSERT INTO Tabs
    (`timestamp`, `id`)
VALUES
    ('2015-01-01', 1),
    ('2015-01-01', 2),
    ('2015-01-02', 3),
    ('2015-01-02', 4),
    ('2015-01-02', 5),
    ('2015-01-04', 6),
    ('2015-01-05', 7),
    ('2015-01-05', 8)
; 
Run Code Online (Sandbox Code Playgroud)

当我使用此查询时:

SELECT `timestamp`, COUNT(*)
FROM Tabs
GROUP BY `timestamp`
Run Code Online (Sandbox Code Playgroud)

我得到了结果:

timestamp   COUNT(*)
2015-01-01  2
2015-01-02  3
2015-01-04  1
2015-01-05  2
Run Code Online (Sandbox Code Playgroud)

但我也需要2015-01-03with 0,所以对我来说正确的输出是:

timestamp   COUNT(*)
2015-01-01  2
2015-01-02  3
2015-01-02  0
2015-01-04  1
2015-01-05  2
Run Code Online (Sandbox Code Playgroud)

请问我怎样才能意识到呢?

Jul*_*eur 5

我想你知道的date_startdate_end,尽管它可以扩展你不会超过1000个工作日内上。

此示例适用于以下值:

SET @date_start := CAST('20150101' as date);
SET @date_end := CAST('20150108' as date);
Run Code Online (Sandbox Code Playgroud)

以下查询在@date_start(2015-01-01) 和@date_end(2015-01-08)之间每天返回。这类似于日历。然后,完整的天数列表可以是LEFT JOIN表中可用天数的列表。

使用 SELECT ... UNION ALL ...

SELECT @date := date_add(@date, INTERVAL 1 DAY) as date
FROM (
    SELECT 0 as 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
  )d10, (
    SELECT 0 as 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   
  )d100, (
    SELECT 0 as 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   
  ) d1000
  , (SELECT @date := date_add(@date_start, INTERVAL -1 DAY)) v
WHERE @date < @date_end
;
Run Code Online (Sandbox Code Playgroud)

输出:

date
2015-01-01
2015-01-02
2015-01-03
2015-01-04
2015-01-05
2015-01-06
2015-01-07
2015-01-08
Run Code Online (Sandbox Code Playgroud)
  • 每个内部SELECT ... UNION ALL ...返回 0 到 9 的 10 行
  • SELECT被使用了CROSS JOIN3 次并从第 0 天到第 999 天返回 1000 行(10*10*10)
  • 因为@date加1,所以最多可以返回1000个连续天数
  • 如果再添加一个,则可以工作 10.000 天SELECT ... UNION ALL ...,依此类推,如果删除第三个连接,则可以工作100天
  • 然后,您可以将这个查询与您的表 LEFT JOIN

使用视图

创建一个数字从 0 到 9 的视图并 CROSS JOIN 它 3 次或创建 1 个从 0 到 999 的单个视图可能更容易:

CREATE VIEW viewDec As
  SELECT 0 as 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
;    

SELECT @date := date_add(@date, INTERVAL 1 DAY) as date
FROM viewDec d10, viewDec d100, viewDec d1000
    , (SELECT @date := date_add(@date_start, INTERVAL -1 DAY)) v
WHERE @date < @date_end
;
Run Code Online (Sandbox Code Playgroud)
  • 您可以通过添加额外的viewDec d10000...工作 10.000 天

使用现有表

也可以将SELECT或替换为VIEW具有足够行(在本例中为 1000)的现有表:

SELECT @date := date_add(@date, INTERVAL 1 DAY) as date
FROM (SELECT 1 as n FROM table_with_over_1000_rows LIMIT 1000) t
    , (SELECT @date := date_add(@date_start, INTERVAL -1 DAY)) v
WHERE @date < @date_end
;
Run Code Online (Sandbox Code Playgroud)

完整查询(使用 viewDec)

SELECT `date`, count(t.`id`)
FROM (
  SELECT @date := date_add(@date, INTERVAL 1 DAY) as date
  FROM viewDec d10, viewDec d100, viewDec d1000
    , (SELECT @date := date_add(@date_start, INTERVAL -1 DAY)) v
  WHERE @date < @date_end  
) d
LEFT JOIN (
    SELECT `id`, `timestamp`
    FROM Tabs
    /* WHERE sensor = 10 */
) t
    ON d.`date` = t.`timestamp`
GROUP BY d.`date`
;
Run Code Online (Sandbox Code Playgroud)

在此SQL Fiddle timestamp中,已替换为类型日期列。

输出:

date        count(t.`id`)
2015-01-01  2
2015-01-02  3
2015-01-03  0
2015-01-04  1
2015-01-05  2
2015-01-06  0
2015-01-07  0
2015-01-08  0
Run Code Online (Sandbox Code Playgroud)