计算Postgresql中的累计总数

时间:2011-04-18 04:14:47

标签: sql postgresql aggregate-functions

我正在使用countgroup 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

6 个答案:

答案 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 )

然后,您可以加入此表格以对您需要的字段进行汇总。

相关问题