连续 ID 块上的 PostgresQL 窗口函数
Posted
技术标签:
【中文标题】连续 ID 块上的 PostgresQL 窗口函数【英文标题】:PostgresQL window function over blocks of continuous IDs 【发布时间】:2021-04-14 11:43:53 【问题描述】:我有一个带有部分连续整数 id 的表,即有诸如 1,2,3, 6,7,8, 10, 23,24,25,26
之类的块。
我对从表格中选择的简单解决方案感到头疼 并包含一列,其中值对应于相应块的第一个 id。
即像这样的
select id, first(id) over <what goes here?> first from table;
结果应该如下所示
| id | first |
|----|-------|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 6 | 6 |
| 7 | 6 |
| 8 | 6 |
| 10 | 10 |
| 23 | 23 |
| 24 | 23 |
| 25 | 23 |
| 26 | 23 |
之后我可以将此列与partition by
窗口函数子句很好地结合使用。
到目前为止,我想出的总是与此类似,但没有成功:
WITH foo AS (
SELECT LAG(id) OVER (ORDER BY id) AS previous_id,
id AS id,
id - LAG(id, 1, id) OVER (ORDER BY id) AS first_in_sequence
FROM table)
SELECT *,
FIRST_VALUE(id) OVER (ORDER BY id) AS first
FROM foo
ORDER BY id;
定义一个自定义的 postgres 函数也是一个可接受的解决方案。
感谢您的建议,
马蒂
【问题讨论】:
【参考方案1】:在 Postgres 中你可以create a custom aggregate. 示例:
create or replace function first_in_series_func(int[], int)
returns int[] language sql immutable
as $$
select case
when $1[2] is distinct from $2- 1 then array[$2, $2]
else array[$1[1], $2] end;
$$;
create or replace function first_in_series_final(int[])
returns int language sql immutable
as $$
select $1[1]
$$;
create aggregate first_in_series(int) (
sfunc = first_in_series_func,
finalfunc = first_in_series_final,
stype = int[]
);
Db<>fiddle.
阅读文档:User-Defined Aggregates
【讨论】:
太棒了。我接受这一点,因为我觉得它是解决它的更具声明性的方式。它可能也是一个更容易转移到类似问题的解决方案,并指出我相应的文档:) 创建聚合函数的能力是 Postgres 的一大亮点。我很乐意提供自定义聚合的示例,因为人们认为这很困难,但实际上比乍一看容易。【参考方案2】:这是一个如何做到这一点的想法。不过,隐式游标的效率并不高。
create or replace function ff()
returns table (r_id integer, r_first integer)
language plpgsql as
$$
declare
running_previous integer;
running_id integer;
running_first integer := null;
begin
for running_id in select id from _table order by id loop
if running_previous is distinct from running_id - 1 then
running_first := running_id;
end if;
r_id := running_id;
r_first := running_first;
running_previous := running_id;
return next;
end loop;
end
$$;
-- test
select * from ff() as t(id, first);
【讨论】:
以上是关于连续 ID 块上的 PostgresQL 窗口函数的主要内容,如果未能解决你的问题,请参考以下文章