为不存在的数据返回空行

问题描述 投票:2回答:2

好,我有一个带有date列和integer列的表,我想检索所有行在特定日期范围内按日期进行分组;由于没有每天的行,是否有可能使mysql返回带有默认值的那几天的行?

示例

源表:

date         value
2020-01-01   1
2020-01-01   2
2020-01-03   2
2020-01-07   3
2020-01-08   4
2020-01-08   1

按日期groupsum定位值后的标准行为:

2020-01-01   3
2020-01-03   2
2020-01-07   3
2020-01-08   5

具有空行的所需行为/结果:

2020-01-01   3
2020-01-02   0
2020-01-03   2
2020-01-04   0
2020-01-05   0
2020-01-06   0
2020-01-07   3
2020-01-08   5
mysql group-by rows intervals
2个回答
2
投票

您可以执行以下操作:

# table creation:

drop table if exists test_table;

create table test_table (your_date date, your_value int(11));
insert into test_table (your_date, your_value) values ('2020-01-01', 1);
insert into test_table (your_date, your_value) values ('2020-01-01', 2);
insert into test_table (your_date, your_value) values ('2020-01-03', 2);
insert into test_table (your_date, your_value) values ('2020-01-07', 3);
insert into test_table (your_date, your_value) values ('2020-01-08', 4);
insert into test_table (your_date, your_value) values ('2020-01-08', 1);

这将创建一个基本上所有日期的列表。然后,您可以过滤感兴趣的日期,并与表和组一起加入。

您还可以用子查询(表的最小和最大日期)替换where语句中的日期,以使其具有动态性

这是一种变通方法,但是可以。

select sbqry.base_date, sum(ifnull(t.your_value, 0))
from (select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) base_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) sbqry
left join test_table t on base_date = t.your_date
where sbqry.base_date between '2020-01-01' and '2020-01-08'
group by sbqry.base_date;

输入:

+------------+------------+
| your_date  | your_value |
+------------+------------+
| 2020-01-01 |          1 |
| 2020-01-01 |          2 |
| 2020-01-03 |          2 |
| 2020-01-07 |          3 |
| 2020-01-08 |          4 |
| 2020-01-08 |          1 |
+------------+------------+

输出:

+------------+------------------------------+
| base_date  | sum(ifnull(t.your_value, 0)) |
+------------+------------------------------+
| 2020-01-01 |                            3 |
| 2020-01-02 |                            0 |
| 2020-01-03 |                            2 |
| 2020-01-04 |                            0 |
| 2020-01-05 |                            0 |
| 2020-01-06 |                            0 |
| 2020-01-07 |                            3 |
| 2020-01-08 |                            5 |
+------------+------------------------------+

2
投票

您还可以通过以下查询来实现所需的目的,这可能更易于理解:

SELECT
     date_table.date,
     IFNULL(SUM(value),0) as sum_val
FROM (
     SELECT DATE_ADD('2020-01-01', INTERVAL (@i:=@i+1)-1 DAY) AS `date`
     FROM information_schema.columns,(SELECT @i:=0) gen_sub
     WHERE DATE_ADD('2020-01-01',INTERVAL @i DAY) BETWEEN '2020-01-01' AND '2020-01-08'
) date_table
LEFT JOIN test ON test.date_value = date_table.date
GROUP BY date;

FIND A DEMO HERE

您可以设置一些变量来确定最小和最大日期:

SET @date_min = '2020-01-01';
SET @date_max = '2020-01-08';

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

一些解释:

实际上,您的问题鼓励我们生成一组日期,因为我们希望使用一组连续的日期来“左联接”“您的表”,以匹配“您的表”中没有记录的日期。

由于generate_series函数,这在PostgreSQL中非常容易,但是在MySQL中却不那么容易,因为这样的有用函数不存在。这就是为什么我们需要变得聪明。

这两个解决方案都具有相同的逻辑:我的意思是,它们都为连接到另一个表中的每一行都增加一个日期值(每天),我们称之为“源表”。在上面的答案中(不是我的),“源表”由许多联合和交叉联接构成(生成10万行),在我的情况下,“源表”是“ information_schema.columns”,其中已经包含很多行(1800) +)。

在上述情况下,初始日期固定为1970-01-01,然后它将使该日期递增10万次,以便获得一组以1970-01-01开始的100000个日期。

对于我来说,初始日期固定为您的最小范围日期2020-01-01,然后它将对在information_schema.columns中找到的每一行增加该日期,因此大约是1800次。从2020-01-01开始,您将获得大约1800个日期。

最后,您可以将生成的日期集(无论采用哪种方式)加入表中,以便将所需范围内的每一天相加(值)。

希望可以帮助您了解两个查询背后的逻辑;)

© www.soinside.com 2019 - 2024. All rights reserved.