Kol*_*olM 6 sql postgresql greatest-n-per-group window-functions
我有这样一张桌子:
Name activity time
user1 A1 12:00
user1 E3 12:01
user1 A2 12:02
user2 A1 10:05
user2 A2 10:06
user2 A3 10:07
user2 M6 10:07
user2 B1 10:08
user3 A1 14:15
user3 B2 14:20
user3 D1 14:25
user3 D2 14:30
Run Code Online (Sandbox Code Playgroud)
现在,我需要这样的结果:
Name activity next_activity
user1 A2 NULL
user2 A3 B1
user3 A1 B2
Run Code Online (Sandbox Code Playgroud)
我想检查每个用户A组的最后一项活动以及接下来B组的活动类型(B组的活动总是在A组活动后进行).其他类型的活动对我来说并不感兴趣.我试过使用该lead()
功能,但它没有奏效.
我怎么能解决我的问题?
测试设置:
CREATE TEMP TABLE t (name text, activity text, time time);
INSERT INTO t values
('user1', 'A1', '12:00')
,('user1', 'E3', '12:01')
,('user1', 'A2', '12:02')
,('user2', 'A1', '10:05')
,('user2', 'A2', '10:06')
,('user2', 'A3', '10:07')
,('user2', 'M6', '10:07')
,('user2', 'B1', '10:08')
,('user3', 'A1', '14:15')
,('user3', 'B2', '14:20')
,('user3', 'D1', '14:25')
,('user3', 'D2', '14:30');
Run Code Online (Sandbox Code Playgroud)
你的定义:
B组的活动总是在A组活动后进行.
..逻辑上暗示在一个或多个A活动之后,每个用户有0或1个B活动.按顺序进行的活动不得超过1个.
你可以把它与一个窗口功能的工作,DISTINCT ON
并且CASE
,这应该是最快的方式很少每个用户行(见下文):
SELECT name
, CASE WHEN a2 LIKE 'B%' THEN a1 ELSE a2 END AS activity
, CASE WHEN a2 LIKE 'B%' THEN a2 END AS next_activity
FROM (
SELECT DISTINCT ON (name)
name
, lead(activity) OVER (PARTITION BY name ORDER BY time DESC) AS a1
, activity AS a2
FROM t
WHERE (activity LIKE 'A%' OR activity LIKE 'B%')
ORDER BY name, time DESC
) sub;
Run Code Online (Sandbox Code Playgroud)
如果没有添加分支,则SQL CASE
表达式默认为,所以我保持简短.NULL
ELSE
也假定time
是定义的NOT NULL
.否则,您可能想要添加NULLS LAST
.为什么?
(activity LIKE 'A%' OR activity LIKE 'B%')
比activity ~ '^[AB]'
旧版本的Postgres 更加冗长,但通常更快.关于模式匹配:
这实际上是可能的.您可以将aggregate FILTER
子句与OVER
window函数的子句组合在一起.但是:
该FILTER
条款本身只能从当前行值工作.
更重要的是, FILTER
没有实现像纯窗函数lead()
或lag()
在Postgres的9.6(还) -仅适用于聚集函数.
如果你试试:
lead(activity) FILTER (WHERE activity LIKE 'A%') OVER () AS activity
Run Code Online (Sandbox Code Playgroud)
Postgres会告诉你:
Run Code Online (Sandbox Code Playgroud)FILTER is not implemented for non-aggregate window functions
关于 FILTER
:
(对于少数用户数每个用户行,几乎任何查询速度快,即使没有索引).
对于许多用户和每个用户几行,上面的第一个查询应该是最快的.查看链接的答案上面关于索引和性能.
对于每个用户的许多行,有(可能更多)更快的技术,具体取决于您的设置的其他详细信息:
select distinct on(name) name,activity,next_activity
from (select name,activity,time
,lead(activity) over (partition by name order by time) as next_activity
from t
where left(activity,1) in ('A','B')
) t
where left(activity,1) = 'A'
order by name,time desc
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
9220 次 |
最近记录: |