使用PostgreSQL

时间:2017-12-22 13:54:52

标签: sql postgresql

我的表用户具有以下值:

  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

我想:

  • 查找一段时间内用户数的累计总和(返回日期范围内每天的用户数,而不仅仅是数据库中存在的天数)
  • 能够按日期过滤该总和,所以如果我把日期放在某一行之后,该行应该包含在累积总和中(指定范围之前的所有内容都应该包含在第一个总和中,它不应该&# 39; 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

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

非常感谢任何帮助。

1 个答案:

答案 0 :(得分: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;