一个sql查询中来自不同条件的多个聚合总和

时间:2016-03-29 13:53:47

标签: sql postgresql

虽然我认为这是一个相当普遍的SQL问题,但我在PostgreSQL 9.4中工作,没有使用其他数据库软件的选项,因此请求任何答案与其功能兼容。

我需要能够从一个查询返回多个聚合总计,这样每个总和都在一个新行中,并且每个分组由唯一的时间跨度确定,例如, WHERE time_stamp BETWEEN '2016-02-07' AND '2016-02-14'。满足WHERE子句的记录数是未知的,可能为零,在这种情况下,理想情况下结果为“0”。这是我到目前为止所做的:

(
SELECT SUM(minutes) AS min
FROM downtime
WHERE time_stamp BETWEEN '2016-02-07' AND '2016-02-14'
)
UNION ALL
(
SELECT SUM(minutes)
FROM downtime
WHERE time_stamp BETWEEN '2016-02-14' AND '2016-02-21'
)
UNION ALL
(
SELECT SUM(minutes)
FROM downtime
WHERE time_stamp BETWEEN '2016-02-28' AND '2016-03-06'
)
UNION ALL
(
SELECT SUM(minutes)
FROM downtime
WHERE time_stamp BETWEEN '2016-03-06' AND '2016-03-13'
)
UNION ALL
(
SELECT SUM(minutes))
FROM downtime
WHERE time_stamp BETWEEN '2016-03-13' AND '2016-03-20'
)
UNION ALL
(
SELECT SUM(minutes)
FROM downtime
WHERE time_stamp BETWEEN '2016-03-20' AND '2016-03-27'
)

结果:

     min
---+-----
 1 | 119
 2 |   4
 3 |  30
 4 |   
 5 |  62 
 6 | 350

该查询让我几乎我想要的确切结果;肯定是足够好的,因为我可以完成我所需的结果。没有记录的时间跨度是空白的,但这是可预测的,而我更喜欢“0”,我可以在软件中考虑空行。

但是,虽然它代表的6个星期并不可怕,但我想要灵活,能够针对不同的时间跨度和不同数量的数据点执行相同的操作,例如每个一周中的一天,每周一次的3个月,6个月,每个月的1年,2年等等......如上所述,感觉好像很快就会变得乏味......例如1周的跨度超过2年的时间是104个子查询。

我所追求的是获得相同(或类似)结果的更优雅方式。

我也不知道是否对上述类似查询进行了104次迭代(相对于现在的6次)是一种特别有效的用法。

最终,我将编写一些代码来帮助我构建(并因此抽象出来)冗长,丑陋的查询 - 但是拥有更简洁和可扩展的查询仍然会很棒。

1 个答案:

答案 0 :(得分:1)

在Postgres中,您可以生成一系列时间,然后将这些用于聚合:

select g.dte, coalesce(sum(dt.minutes), 0) as minutes
from generate_series('2016-02-07'::timestamp, '2016-03-20'::timestamp, interval '7 day') g(dte) left join
     downtime dt
     on dt.timestamp >= g.dte and dt.timestamp < g.dte + interval '7 day'
group by g.dte
order by g.dte;