max*_*ire 15 postgresql window-functions
考虑一个记录访问的表
create table visits (
person varchar(10),
ts timestamp,
somevalue varchar(10)
)
Run Code Online (Sandbox Code Playgroud)
考虑这个示例数据(时间戳简化为计数器)
ts| person | somevalue
-------------------------
1 | bob |null
2 | bob |null
3 | jim |null
4 | bob | A
5 | bob | null
6 | bob | B
7 | jim | X
8 | jim | Y
9 | jim | null
Run Code Online (Sandbox Code Playgroud)
我试图将这个人的最后一个非空值传递到他未来的所有访问中,直到该值发生变化(即成为下一个非空值)。
预期结果集如下所示:
ts| person | somevalue | carry-forward
-----------------------------------------------
1 | bob |null | null
2 | bob |null | null
3 | jim |null | null
4 | bob | A | A
5 | bob | null | A
6 | bob | B | B
7 | jim | X | X
8 | jim | Y | Y
9 | jim | null | Y
Run Code Online (Sandbox Code Playgroud)
我的尝试是这样的:
select *,
first_value(somevalue) over (partition by person order by (somevalue is null), ts rows between UNBOUNDED PRECEDING AND current row ) as carry_forward
from visits
order by ts
Run Code Online (Sandbox Code Playgroud)
注意:(somevalue is null) 为排序的目的计算为 1 或 0,因此我可以获得分区中的第一个非空值。
以上没有给我我想要的结果。
max*_*ire 17
以下查询达到了预期的结果:
select *, first_value(somevalue) over w as carryforward_somevalue
from (
select *, sum(case when somevalue is null then 0 else 1 end) over (partition by person order by id ) as value_partition
from test1
) as q
window w as (partition by person, value_partition order by id);
Run Code Online (Sandbox Code Playgroud)
请注意 null case 语句 - 如果 postgres 窗口函数支持 IGNORE_NULL,则不需要此语句(如@ypercube 所述??)
这个问题属于间隙和岛屿问题。遗憾的是,Postgres 还没有IGNORE NULL
在像 那样的窗口函数中实现FIRST_VALUE()
,否则它会变得微不足道,只需在您的查询中进行简单的更改即可。
使用窗口函数或递归 CTE 可能有很多方法可以解决这个问题。
不确定这是否是最有效的方法,但递归 CTE 确实解决了问题:
with recursive
cf as
(
( select distinct on (person)
v.*, v.somevalue as carry_forward
from visits as v
order by person, ts
)
union all
select
v.*, coalesce(v.somevalue, cf.carry_forward)
from cf
join lateral
( select v.*
from visits as v
where v.person = cf.person
and v.ts > cf.ts
order by ts
limit 1
) as v
on true
)
select cf.*
from cf
order by ts ;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
12650 次 |
最近记录: |