查询滚动日期范围内的不同值的计数

时间:2012-05-11 01:14:37

标签: sql postgresql date count

我有一组电子邮件地址和日期,这些电子邮件地址已添加到表格中。对于不同的日期,可以有多个电子邮件地址条目。例如,如果我有下面的数据集。我希望得到我们在所述日期和3天前之间的不同电子邮件的日期和数量。

Date   | email  
-------+----------------
1/1/12 | test@test.com
1/1/12 | test1@test.com
1/1/12 | test2@test.com
1/2/12 | test1@test.com
1/2/12 | test2@test.com
1/3/12 | test@test.com
1/4/12 | test@test.com
1/5/12 | test@test.com
1/5/12 | test@test.com
1/6/12 | test@test.com
1/6/12 | test@test.com
1/6/12 | test1@test.com

如果我们使用日期3

,结果集看起来会像这样
date   | count(distinct email)
-------+------
1/1/12 | 3
1/2/12 | 3
1/3/12 | 3
1/4/12 | 3
1/5/12 | 2
1/6/12 | 2

我可以使用下面的查询获得日期范围的明确计数,但是希望按天计算范围,因此我不必手动更新数百个日期的范围。

select test.date, count(distinct test.email)  
from test_table as test  
where test.date between '2012-01-01' and '2012-05-08'  
group by test.date;

非常感谢帮助。

5 个答案:

答案 0 :(得分:11)

测试用例:

CREATE TEMP TABLE tbl (day date, email text);
INSERT INTO tbl VALUES
 ('2012-01-01', 'test@test.com')
,('2012-01-01', 'test1@test.com')
,('2012-01-01', 'test2@test.com')
,('2012-01-02', 'test1@test.com')
,('2012-01-02', 'test2@test.com')
,('2012-01-03', 'test@test.com')
,('2012-01-04', 'test@test.com')
,('2012-01-05', 'test@test.com')
,('2012-01-05', 'test@test.com')
,('2012-01-06', 'test@test.com')
,('2012-01-06', 'test@test.com')
,('2012-01-06', 'test1@test.com`');

查询 - 仅返回tbl中存在条目的日期:

SELECT day
     ,(SELECT count(DISTINCT email)
       FROM   tbl
       WHERE  day BETWEEN t.day - 2 AND t.day -- period of 3 days
      ) AS dist_emails
FROM   tbl t
WHERE  day BETWEEN '2012-01-01' AND '2012-01-06'  
GROUP  BY 1
ORDER  BY 1;

或 - 在指定范围内返回所有天,即使当天没有行:

SELECT day
     ,(SELECT count(DISTINCT email)
       FROM   tbl
       WHERE  day BETWEEN g.day - 2 AND g.day
      ) AS dist_emails
FROM  (SELECT generate_series('2012-01-01'::date
                            , '2012-01-06'::date, '1d')::date) AS g(day)

结果:

day        | dist_emails
-----------+------------
2012-01-01 | 3
2012-01-02 | 3
2012-01-03 | 3
2012-01-04 | 3
2012-01-05 | 1
2012-01-06 | 2

这听起来像window functions的作业,但我找不到定义合适窗框的方法。另外,per documentation

  

与普通聚合函数不同,聚合窗口函数不会   允许在函数参数列表中使用DISTINCTORDER BY

所以我用相关的子查询解决了它。我猜这是最聪明的方式。

我将您的日期列重命名为day,因为将类型名称用作标识符是不好的做法。

顺便说一下,“在所述日期和3天前之间”将是 4 天的时期。你的定义在那里是矛盾的。

有点短,但只有几天慢了:

SELECT day, count(DISTINCT email) AS dist_emails
FROM  (SELECT generate_series('2013-01-01'::date
                            , '2013-01-06'::date, '1d')::date) AS g(day)
LEFT   JOIN tbl t ON t.day BETWEEN g.day - 2 AND g.day
GROUP  BY 1
ORDER  BY 1;

答案 1 :(得分:0)

在sql server中:

`select test.date, count(distinct test.email) from test_table as test  where convert(date,test.date) between '2012-01-01' and '2012-05-08' group by test.date`

希望这会有所帮助。

答案 2 :(得分:0)

您可以随时使用dateadd函数,而不是指定日期:

test.date > dateadd(dd,-7,getdate())

答案 3 :(得分:0)

滑动窗口非重复计数的示例:

SELECT b.day, count(DISTINCT a.user_id)
from glip_production.presences_1d a,
 (SELECT distinct(day), TIMESTAMPADD(day,-6, day) dt_start
  from glip_production.presences_1d t1) b
where a.day >= b.dt_start and a.day <= b.day and b.day > '2017-11-01'
group by b.day

答案 4 :(得分:0)

"workbench.editor.decorations.badges":false, 对于此类“滑动窗口”需求很有用,如下所示:

lateral join

请注意,这是 Erwin Brandstetter 之前查询的一个变体,令我惊讶的是他没有提出建议,但这些横向连接非常适合此类需求。