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
请注意上述分区中的子分区date
当is_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 查询不是聚合函数的一部分。使用计数功能