PostgresQL window 在连续 ID 块上运行
PostgresQL window function over blocks of continuous IDs
我有一个 table 具有部分连续的整数 ID,即有 1,2,3, 6,7,8, 10, 23,24,25,26
.
这样的块
- 间隙大小是动态的
- 块的长度是动态的
我对从 table 中选择的 简单 解决方案感到头疼
并包含一列,其中的值对应于相应块的第一个 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
window 函数子句很好地结合使用。
到目前为止我想出的总是看起来与此相似但没有成功:
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 函数也是一个可接受的table解决方案。
感谢任何建议,
马蒂
这是一个如何做到这一点的想法。隐式游标虽然效率不高。
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);
在 Postgres 中,您可以 create a custom aggregate. 示例:
create or replace function first_in_series_func(int[], int)
returns int[] language sql immutable
as $$
select case
when [2] is distinct from - 1 then array[, ]
else array[[1], ] end;
$$;
create or replace function first_in_series_final(int[])
returns int language sql immutable
as $$
select [1]
$$;
create aggregate first_in_series(int) (
sfunc = first_in_series_func,
finalfunc = first_in_series_final,
stype = int[]
);
我有一个 table 具有部分连续的整数 ID,即有 1,2,3, 6,7,8, 10, 23,24,25,26
.
- 间隙大小是动态的
- 块的长度是动态的
我对从 table 中选择的 简单 解决方案感到头疼 并包含一列,其中的值对应于相应块的第一个 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
window 函数子句很好地结合使用。
到目前为止我想出的总是看起来与此相似但没有成功:
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 函数也是一个可接受的table解决方案。
感谢任何建议,
马蒂
这是一个如何做到这一点的想法。隐式游标虽然效率不高。
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);
在 Postgres 中,您可以 create a custom aggregate. 示例:
create or replace function first_in_series_func(int[], int)
returns int[] language sql immutable
as $$
select case
when [2] is distinct from - 1 then array[, ]
else array[[1], ] end;
$$;
create or replace function first_in_series_final(int[])
returns int language sql immutable
as $$
select [1]
$$;
create aggregate first_in_series(int) (
sfunc = first_in_series_func,
finalfunc = first_in_series_final,
stype = int[]
);