我正在使用count
和group by
来获取每天注册的订阅者数量:
SELECT created_at, COUNT(email)
FROM subscriptions
GROUP BY created at;
结果:
created_at count
-----------------
04-04-2011 100
05-04-2011 50
06-04-2011 50
07-04-2011 300
我想每天获得累计订阅者总数。我怎么得到这个?
created_at count
-----------------
04-04-2011 100
05-04-2011 150
06-04-2011 200
07-04-2011 500
答案 0 :(得分:86)
对于较大的数据集,window functions是执行这些类型查询的最有效方式 - 表格将只扫描一次,而不是每个日期扫描一次,就像自联接一样。它看起来也简单得多。 :) PostgreSQL 8.4及以上版本支持窗口函数。
这就是它的样子:
SELECT created_at, sum(count(email)) OVER (ORDER BY created_at)
FROM subscriptions
GROUP BY created_at;
这里OVER
创建窗口; ORDER BY created_at
表示必须按created_at
顺序汇总计数。
修改:如果您想在一天内删除重复的电子邮件,可以使用sum(count(distinct email))
。不幸的是,这不会删除跨越不同日期的重复项。
如果要删除所有重复项,我认为最简单的方法是使用子查询和DISTINCT ON
。这会将电子邮件归因于他们最早的日期(因为我按升序排序created_at,它会选择最早的日期):
SELECT created_at, sum(count(email)) OVER (ORDER BY created_at)
FROM (
SELECT DISTINCT ON (email) created_at, email
FROM subscriptions ORDER BY email, created_at
) AS subq
GROUP BY created_at;
如果您在(email, created_at)
上创建索引,则此查询也不应太慢。
(如果你想测试,这就是我创建样本数据集的方式)
create table subscriptions as
select date '2000-04-04' + (i/10000)::int as created_at,
'foofoobar@foobar.com' || (i%700000)::text as email
from generate_series(1,1000000) i;
create index on subscriptions (email, created_at);
答案 1 :(得分:6)
使用:
SELECT a.created_at,
(SELECT COUNT(b.email)
FROM SUBSCRIPTIONS b
WHERE b.created_at <= a.created_at) AS count
FROM SUBSCRIPTIONS a
答案 2 :(得分:2)
SELECT
s1.created_at,
COUNT(s2.email) AS cumul_count
FROM subscriptions s1
INNER JOIN subscriptions s2 ON s1.created_at >= s2.created_at
GROUP BY s1.created_at
答案 3 :(得分:2)
我假设您每天只想要一行,并且您仍希望显示没有任何订阅的日期(假设没有订阅特定日期,您是否希望显示该日期与前一天的余额?)。如果是这种情况,您可以使用“带”功能:
with recursive serialdates(adate) as (
select cast('2011-04-04' as date)
union all
select adate + 1 from serialdates where adate < cast('2011-04-07' as date)
)
select D.adate,
(
select count(distinct email)
from subscriptions
where created_at between date_trunc('month', D.adate) and D.adate
)
from serialdates D
答案 4 :(得分:0)
致今天(2021 年)看到此答案的任何人 您可以使用汇总
SELECT created_at, COUNT(email)
FROM subscriptions
GROUP BY rollup(created_at);
这将为您提供一个包含总数的新行
created_at count
-----------------
04-04-2011 100
05-04-2011 50
06-04-2011 50
07-04-2011 300
NULL 500
如果您有多个参数在组中显示,您也可以使用汇总来获取部分结果。例如,如果您有 created_by
:
SELECT created_at, created_by COUNT(email)
FROM subscriptions
GROUP BY rollup(created_at, created_by);
这将为您提供一个包含总数的新行
created_at created_by count
-----------------------------
04-04-2011 1 80
04-04-2011 2 20
04-04-2021 NULL 100
05-04-2011 1 20
05-04-2011 2 30
05-04-2011 NULL 50
NULL NULL 150
我只取了前两天的数字,但这就是想法。它将显示按日期分组,然后是当天的总数,然后是总数。
此处 rollup()
中的顺序很重要,关于部分总计的显示方式
答案 5 :(得分:-3)
最好的方法是拥有一个日历表: 日历( 约会日期, 月int, 季度, 半英, 周int, 年int )
然后,您可以加入此表格以对您需要的字段进行汇总。