查询多个日期范围

itc*_*der 0 postgresql

我有 Postgres 9.5 版。我需要通过一个查询来获取日期范围的结果:

2017-02-16 -  2017-02-26
2017-01-16 -  2017-01-26
2016-12-16 -  2016-12-26
2016-11-16 -  2016-11-26
Run Code Online (Sandbox Code Playgroud)

我怎么能用一个查询做到这一点?我试过:

SELECT  sum(sell) as sell
FROM "stat" 
LEFT JOIN "stat_key" ON stat.stat_key = stat_key.id 
WHERE ("stat"."date" >= '2017-02-16' AND stat."date" <= '2017-02-26')
AND ("stat"."date" >= '2017-01-16' AND stat."date" <= '2017-01-26')
AND   ("stat"."date" >= '2016-12-16' AND stat."date" <= '2017-12-26')
Run Code Online (Sandbox Code Playgroud)

但它不起作用。

统计表数据

CREATE TABLE stat
AS
  SELECT date::date, sell
  FROM ( VALUES
    ( '2016-11-14', 0 ),
    ( '2017-01-27', 0 ),
    ( '2017-01-27', 0 ),
    ( '2016-11-10', 0 ),
    ( '2016-11-09', 0 ),
    ( '2016-11-09', 0 ),
    ( '2016-12-30', 0 ),
    ( '2016-11-08', 0 ),
    ( '2016-11-08', 7 ),
    ( '2016-11-08', 0 )
  ) AS t(date, sell);
Run Code Online (Sandbox Code Playgroud)

预期结果

SELECT  sum(sell) as sell
FROM "stat" 
LEFT JOIN "stat_key" ON stat.stat_key = stat_key.id 
WHERE ("stat"."date" >= '2017-02-16' AND stat."date" <= '2017-02-26')
AND ("stat"."date" >= '2017-01-16' AND stat."date" <= '2017-01-26')
AND   ("stat"."date" >= '2016-12-16' AND stat."date" <= '2017-12-26')
Run Code Online (Sandbox Code Playgroud)

Dar*_*rio 5

至少,您应该使用OR代替AND,因为日期不可能同时在二月和AND一月。

SELECT sum(sell) AS sell
  FROM stat 
  LEFT JOIN stat_key ON stat.stat_key = stat_key.id 
 WHERE stat.date BETWEEN '2017-02-16' AND '2017-02-26'
    OR stat.date BETWEEN '2017-01-16' AND '2017-01-26'
    OR stat.date BETWEEN '2016-12-16' AND '2017-12-26';
Run Code Online (Sandbox Code Playgroud)

现在我看到了你的预期输出,我知道你想要这样的东西:

WITH ct(d) AS ( 
  SELECT d::date 
  FROM generate_series('2016-11-26', '2017-02-26', INTERVAL '1 month') AS gs(d)
) 
SELECT COALESCE(SUM(s.sell), 0) AS sell, 
       ct.d AS dt  
    FROM  ct 
    LEFT JOIN stat s ON s.date BETWEEN ct.d + '-10 days' AND ct.d 
    GROUP BY ct.d;
Run Code Online (Sandbox Code Playgroud)

不幸的是,样本输入无法生成您预期的输出,因此我不得不用我的数据对其进行测试。

笔记:

  • generate_series使用时间戳:您可以将它们转换为 mainSELECT或 CTE中的日期。其他方法也是可能的。
  • 可以避免CTE(即WITH开头的)并直接与SELECT generate_series(.... 但是,我发现这种方式更具可读性,因为通过这种方式,报告日期接近顶部,而且这是您最常更改的内容。
  • LEFT JOINCOALESCE()让您显示0数据表中根本没有值的范围的结果 ( )。