SQL 窗口聚合和计数

Posted

技术标签:

【中文标题】SQL 窗口聚合和计数【英文标题】:SQL Windowing Aggregation and Counts 【发布时间】:2020-06-03 08:19:20 【问题描述】:

我正在使用 Redshift/Postgres 数据库。考虑下表:

    +---------------------------------------+
    |              FunkyUsers               |
    +-------+---------+----------+----------+
    |acc_num| user_id |   date   | is_valid |
    +-------+---------+----------+----------+
    |   a1  |    u1   | 20200201 |    true  |
    |   a1  |    u1   | 20200201 |    true  |
    |   a1  |    u1   | 20200311 |    true  |
    |   a1  |    u2   | 20200201 |   false  |
    |   a1  |    u2   | 20200201 |   false  |
    |   a1  |    u2   | 20200201 |   false  |
    |   a1  |    u3   | 20111201 |    true  |
    |   a1  |    u3   | 20111201 |    true  |
    |   a1  |    u3   | 20111201 |    true  |
    +-------+---------+----------+----------+

我喜欢有以下输出:

    +--------------------------------------------------+
    |                  FunkyUsers                      |
    +-------+---------+----------+----------+----------+
    |acc_num| user_id |   date   | is_valid |  count   |
    +-------+---------+----------+----------+----------+
    |   a1  |    u1   | 20200201 |    true  |    2     |
    |   a1  |    u1   | 20200201 |    true  |    2     |
    +-------+---------+----------+----------+----------+
    |   a1  |    u1   | 20200311 |    true  |    2     |
    +-------+---------+----------+----------+----------+
    |   a1  |    u2   | 20200201 |   false  |    0     |
    |   a1  |    u2   | 20200201 |   false  |    0     |
    |   a1  |    u2   | 20200201 |   false  |    0     |
    +-------+---------+----------+----------+----------+
    |   a1  |    u2   | 20111201 |    true  |    1     |
    |   a1  |    u2   | 20111201 |    true  |    1     |
    |   a1  |    u2   | 20111201 |    true  |    1     |
    +-------+---------+----------+----------+----------+

说明:

请注意分区acc_num, user_id 请注意上述分区中的子分区dateis_valid(partition, subpartition) 为真时,为(partition) 增加count 最后is_valid 将在同一(partition, subpartition) 中的每一行具有相同的值

【问题讨论】:

Redshift 还是 Postgres?尽管它们有一些(非常)古老的根源,但它们是截然不同的产品 所以它是红移的后期。我们可以考虑一个 postgress 的解决方案。 "postgres on redshift" 没有意义。它是 Postgres 或 Redshift。引用Redshift manual“不要假设 Amazon Redshift 和 PostgreSQL 的共同元素的语义是相同的 @Nick,感谢您的回复。因此,每个分区的计数都会增加(即 acc_num、user_id)。所以对于那个分区,子分区有 2 个有效状态。 啊,我明白了。我会删除评论。 【参考方案1】:

据我了解,您希望为用户计算 is_valid = 1 的不同日期。 您可以将窗口函数计数与不同的日期参数一起使用。

select 
    acc_num, user_id, date, is_valid, 
    count(distinct case when is_valid then date end) over (partition by acc_num, user_id, is_valid)
from FunkyUsers

有人告诉我,在 Redshift 的窗口函数中不能使用 distinct。 因此,您可以使用以下查询:

with
counts as
(
    SELECT acc_num, user_id, is_valid, COUNT(DISTINCT CASE WHEN is_valid THEN date END) as count
    FROM FunkyUsers
    GROUP BY acc_num, user_id, is_valid
)
SELECT f.*, c.count
FROM FunkyUsers f
LEFT JOIN counts c
    ON f.acc_num = c.acc_num
    AND f.user_id = c.user_id
    AND f.is_valid = c.is_valid

【讨论】:

你不能在窗口函数中使用distinct 感谢您的回复,但它返回 3 而不是 2。 我忘记将 is_Valid 添加到分区。可以再试一次吗? 不幸的是,它说不支持窗口功能。 然后,添加了另一个解决方案。我相信它会起作用的。【参考方案2】:

您可以使用窗口函数sum进行分区:

select acc_num, user_id, date, is_valid, 
       sum(case when is_valid then 1 end) over(partition by acc_num, user_id, date)
from FunkyUsers

【讨论】:

感谢您的回复,但它返回 3 而不是 2。 @Stacky 3 什么? 不用担心,Sabri 的解决方案奏效了。再次感谢您的帮助。【参考方案3】:

count(distinct) 不受支持。但是一个简单的解决方法是使用row_number()

select fu.*,
       sum(case when is_valid and seqnum = 1 then 1 else 0 end) over (partition by acc_num, user_id order by date) as count
from (select fu.*,
             row_number() over (partition by acc_num, user_id, date order by date) as seqnum
      from funkyusers fu
     ) fu;

这比使用聚合和join 的解决方案要简单得多,而且性能也应该更好。

【讨论】:

感谢您的回复。当我收到你的时,我已经尝试了另一种解决方案,它对我的​​问题有效。还是谢谢。 @Stacky 。 . .这是一个更简单的解决方案,并且性能也应该更好。

以上是关于SQL 窗口聚合和计数的主要内容,如果未能解决你的问题,请参考以下文章

MS Access Sql 查询不是聚合函数的一部分。使用计数功能

Flink 滑动计数窗口行为

SQL聚合函数

SQL窗口函数计数前10查询postgresql redshift

SQL 滚动窗口唯一计数

SQL语句汇总(三)——聚合函数分组子查询及组合查询 - Darly