获取不同子组中的值计数
Posted
技术标签:
【中文标题】获取不同子组中的值计数【英文标题】:Get count of values in different subgroups 【发布时间】:2021-10-31 09:22:48 【问题描述】:我需要删除数据集中的一些行,其中speed
等于零并持续 N 次(假设 N 为 2)。
表demo
的结构如下:
id | car | speed | time |
---|---|---|---|
1 | foo | 0 | 1 |
2 | foo | 0 | 2 |
3 | foo | 0 | 3 |
4 | foo | 1 | 4 |
5 | foo | 1 | 5 |
6 | foo | 0 | 6 |
7 | bar | 0 | 1 |
8 | bar | 0 | 2 |
9 | bar | 5 | 3 |
10 | bar | 5 | 4 |
11 | bar | 5 | 5 |
12 | bar | 5 | 6 |
然后我希望使用window_function
生成如下表:
id | car | speed | time | lasting |
---|---|---|---|---|
1 | foo | 0 | 1 | 3 |
2 | foo | 0 | 2 | 3 |
3 | foo | 0 | 3 | 3 |
4 | foo | 1 | 4 | 2 |
5 | foo | 1 | 5 | 2 |
6 | foo | 0 | 6 | 1 |
7 | bar | 0 | 1 | 2 |
8 | bar | 0 | 2 | 2 |
9 | bar | 5 | 3 | 4 |
10 | bar | 5 | 4 | 4 |
11 | bar | 5 | 5 | 4 |
12 | bar | 5 | 6 | 4 |
然后我可以使用WHERE NOT (speed = 0 AND lasting > 2)
轻松排除这些行
把我试过的代码放在这里,但它没有返回我期望的值,我猜那些FROM (SELECT ... FROM (SELECT ...
可能不是解决问题的最佳实践:
SELECT g3.*, count(id) OVER (PARTITION BY car, cumsum ORDER BY id) as num
FROM (SELECT g2.*, sum(grp2) OVER (PARTITION BY car ORDER BY id) AS cumsum
FROM (SELECT g1.*, (CASE ne0 WHEN 0 THEN 0 ELSE 1 END) AS grp2
FROM (SELECT g.*, speed - lag(speed, 1, 0) OVER (PARTITION BY car) AS ne0
FROM (SELECT *, row_number() OVER (PARTITION BY car) AS grp FROM demo) g ) g1 ) g2 ) g3
ORDER BY id;
【问题讨论】:
【参考方案1】:您可以使用窗口函数 LAG()
检查每行的前一个 speed
值,并使用 SUM()
窗口函数为连续值创建组。
然后使用COUNT()
窗口函数可以统计每组的行数,这样就可以过滤掉超过2行的组中speed
为0的行:
SELECT id, car, speed, time
FROM (
SELECT *, COUNT(*) OVER (PARTITION BY car, grp) counter
FROM (
SELECT *, SUM(flag::int) OVER (PARTITION BY car ORDER BY time) grp
FROM (
SELECT *, speed <> LAG(speed, 1, speed - 1) OVER (PARTITION BY car ORDER BY time) flag
FROM demo
) t
) t
) t
WHERE speed <> 0 OR counter <= 2
ORDER BY id;
请参阅demo。
【讨论】:
谢谢。我注意到解决方案中的另一点:请问在OVER
短语中使用ORDER BY
的时间。有时我发现查询需要ORDER BY
才能获得正确的反馈,但有时不需要。
@FanLiu 在所有分区的 ORDER BY 子句中使用列 time
更有意义。我使用了id
,因为这是我在您的代码中看到的。
完全同意使用time
字段的想法。我的问题完美解决了。非常感谢:)以上是关于获取不同子组中的值计数的主要内容,如果未能解决你的问题,请参考以下文章