在包含日期范围行的表中,从每行生成一行,包含使用小时数

时间:2017-02-19 00:15:30

标签: sql postgresql

给出一个包含以下行的表:

+----+-------------------------+------------------------+
| ID |        StartDate        |        EndDate         |
+----+-------------------------+------------------------+
|  1 | 2016-02-05 20:00:00.000 | 2016-02-07 5:00:00.000 |
+----+-------------------------+------------------------+

我想制作一个这样的表:

+----+------------+----------+
| ID |    Date    | Duration |
+----+------------+----------+
|  1 | 2016-02-05 |        4 |
|  1 | 2016-02-06 |       24 |
|  1 | 2016-02-07 |        5 |
+----+------------+----------+

这是一个面试风格的问题。我想知道如何解决这个问题。是否可以使用标准的SQL查询语法来完成此操作?或者像pl / pgSQL这样的过程语言需要像这样进行查询吗?

1 个答案:

答案 0 :(得分:0)

基本理念是:

SELECT date_trunc('day', dayhour) as dd,count(*)
FROM (VALUES (1, '2016-02-05 20:00:00.000'::timestamp, '2016-02-07 5:00:00.000'::timestamp)
     ) v(ID, StartDate, EndDate), lateral
    generate_series(StartDate, EndDate, interval '1 hour') g(dayhour) 
GROUP BY dd
ORDER BY dd;

这会增加一个小时,所以这更准确:

SELECT date_trunc('day', dayhour) as dd,count(*)
FROM (VALUES (1, '2016-02-05 20:00:00.000'::timestamp, '2016-02-07 5:00:00.000'::timestamp)
     ) v(ID, StartDate, EndDate), lateral
    generate_series(StartDate, EndDate - interval '1 hour', interval '1 hour') g(dayhour) 
GROUP BY dd
ORDER BY dd;

从技术上讲,不需要lateral(在这种情况下,我会将逗号替换为cross join)。但是,这是横向连接的一个例子,因此明确是好的。

我还应该注意,以上是最简单的方法。但是,group by会降低查询速度。还有其他方法不需要每小时生成一个系列。