【问题标题】:Calculating cumulative sum with date filtering in PostgreSQL在 PostgreSQL 中使用日期过滤计算累积和
【发布时间】:2018-06-05 04:15:47
【问题描述】:

我的表用户具有以下值:

  id   |     created_at
-------+---------------------
 20127 | 2015-01-31 04:23:46
 21468 | 2015-02-04 07:50:34
 21571 | 2015-02-04 08:23:50
 20730 | 2015-03-12 10:20:16
 19955 | 2015-03-30 07:44:35
 20148 | 2015-04-17 13:03:26
 21552 | 2015-05-07 19:00:00
 20145 | 2015-06-02 03:12:46
 21467 | 2015-06-03 13:21:51
 21074 | 2015-07-03 19:00:00

我想:

  • 查找用户数随时间推移的累积总和(返回日期范围内每一天的用户数,而不仅仅是数据库中存在的天数)
  • 能够按日期过滤总和,因此如果我将日期放在某行之后,则该行应包含在累积总和中(指定范围之前的所有内容都应包含在第一个总和中,它应该t 从指定范围开头的 0 开始计数)
  • 以纪元格式返回按每天分组的结果

我正在尝试使用以下 SQL 实现此目的:

    SELECT extract(epoch from created_at)::bigint, 
           sum(count(id)::integer) OVER (ORDER BY created_at)
    FROM data_users
    WHERE created_at IS NOT NULL
    GROUP BY created_at

但它没有按预期工作,因为我无法在此处添加按日期过滤,而不从累积总和中排除记录。此外,它不考虑已错过的天数(用户不存在的天数)。

非常感谢任何帮助。

【问题讨论】:

  • 只需使用子查询,并将过滤放在外部查询中。
  • @GordonLinoff 你能详细说明一下吗?

标签: sql postgresql


【解决方案1】:

据我了解您的问题,使用 GROUP BY 进行简单查询就足够了。您可以使用带有GENERATE_SERIES() 的左外连接来获取该范围内的所有日期。如果你有范围的开始和结束日期,你可以使用这个:

SELECT EXTRACT(EPOCH FROM d)::BIGINT, COALESCE(COUNT(u.id), 0)
FROM GENERATE_SERIES(start, end, '1 DAY'::INTERVAL) d 
    LEFT OUTER JOIN data_users u ON u.created_at::DATE = d
GROUP BY 1 ORDER BY 1

您也可以从表中确定startend

SELECT EXTRACT(EPOCH FROM d.date)::BIGINT, COALESCE(COUNT(u.id), 0)
FROM
    (SELECT GENERATE_SERIES(MIN(created_at)::DATE, MAX(created_at)::DATE, '1 DAY'::INTERVAL) AS date
    FROM data_users) d
    LEFT OUTER JOIN data_users u ON u.created_at::DATE = d.date::DATE
GROUP BY 1 ORDER BY 1;

这会返回:

 date_part  | coalesce 
------------+----------
 1422662400 |        1
 1422748800 |        0
 1422835200 |        0
 1422921600 |        0
 1423008000 |        2
 1423094400 |        0
 1423180800 |        0
...
 1435536000 |        0
 1435622400 |        0
 1435708800 |        0
 1435795200 |        0
 1435881600 |        1

通过此查询,您可以获得开始日期之前行的累积总和:

SELECT EXTRACT(EPOCH FROM GREATEST(d.date, start))::BIGINT, COALESCE(COUNT(u.id), 0)
FROM
    (SELECT GENERATE_SERIES(MIN(created_at)::DATE, MAX(created_at)::DATE, '1 DAY'::INTERVAL) AS date
    FROM data_users) d
    LEFT OUTER JOIN data_users u ON u.created_at::DATE = d.date::DATE
GROUP BY 1 ORDER BY 1;

【讨论】:

  • 第二个查询对u.created_at::DATE = d 抛出错误operator does not exist: date = record。第一个查询有帮助,谢谢。
  • 抱歉,我无法测试查询。我已经修复了它,现在它可以工作了。
  • 嗯,我仍然不确定如何将这些日期与我的查询结合起来,我需要一个累积和,而不是计数。
  • 想通了,谢谢!现在剩下的唯一问题是获取过滤器开始日期之前的所有行的累积总和。
  • 我为此添加了第三个查询。
猜你喜欢
  • 2014-05-15
  • 2021-06-07
  • 1970-01-01
  • 2021-08-19
  • 2020-11-04
  • 1970-01-01
  • 2016-04-17
  • 1970-01-01
相关资源
最近更新 更多