计算由另一个字段上定义的窗口过滤的字段的总和

时间:2015-03-15 15:11:40

标签: sql postgresql aggregate-functions aggregate-filter

我有表event

event_date,
num_events,
site_id

我可以轻松地使用聚合SQL来执行SELECT SUM(num_events) GROUP BY site_id

但我还有另一张表site

site_id,
target_date

我想在num_events,90天,120天等60天内联系target_date,我认为可以轻松完成聚合SQL中的WHERE子句。然而,由于两个挑战,这很复杂:

  1. target_date不是固定的,但每个site_id
  2. 会有所不同
  3. 我希望在同一个表格中输出多个日期范围;所以我无法做一个简单的WHERE来排除event表范围之外的记录。
  4. 我想到的一个解决方法是简单地进行多次查询,每个日期范围一次,然后使用视图将它们粘贴在一起。是否有更简单,更好或更优雅的方式来实现我的目标?

2 个答案:

答案 0 :(得分:0)

您可以这样做:

select sum(case when target_date - event_date < 30 then 1 else 0 end) as within_030,
       sum(case when target_date - event_date < 60 then 1 else 0 end) as within_060,
       sum(case when target_date - event_date < 90 then 1 else 0 end) as within_090    
from event e join
     site s
     on e.site_id = s.site_id;

也就是说,您可以使用条件聚合。我不确定&#34;在60&#34;天意味着。这比目标日期早几天,但类似的逻辑将适用于您所需的。

答案 1 :(得分:0)

在Postgres 9.4中使用new aggregate FILTER clause

假设实际的date数据类型,我们只需添加/减去integer个数字即可。
在n天内解释&#34;&#34; as&#34; +/- n天&#34;:

SELECT site_id, s.target_date
     , sum(e.num_events) FILTER (WHERE e.event_date BETWEEN s.target_date - 30
                                             AND s.target_date + 30) AS sum_30
     , sum(e.num_events) FILTER (WHERE e.event_date BETWEEN s.target_date - 60
                                             AND s.target_date + 60) AS sum_60
     , sum(e.num_events) FILTER (WHERE e.event_date BETWEEN s.target_date - 90
                                             AND s.target_date + 90) AS sum_90
FROM   site  s
JOIN   event e USING (site_id)
WHERE   e.event_date BETWEEN s.target_date - 90
                         AND s.target_date + 90
GROUP  BY 1, 2;

同时将条件添加为WHERE子句以提前排除不相关的行。如果sum_90 event范围之外的行数超过一定数量,那么这应该会快得多。