连续 ID 块上的 PostgresQL 窗口函数

Mar*_*ito 3 postgresql aggregate-functions window-functions

我有一个包含部分连续整数 id 的表,即有诸如1,2,3, 6,7,8, 10, 23,24,25,26.

  • 间隙大小是动态的
  • 块的长度是动态的

我对一个简单的解决方案感到非常困惑,该解决方案从表中进行选择,并包含一个列,其中的值对应于相应块的第一个 id。

即像这样的东西

select id, first(id) over <what goes here?> first from table;
Run Code Online (Sandbox Code Playgroud)

结果应如下所示

| id | first |
|----|-------|
| 1  | 1     |
| 2  | 1     |
| 3  | 1     |
| 6  | 6     |
| 7  | 6     |
| 8  | 6     |
| 10 | 10    |
| 23 | 23    |
| 24 | 23    |
| 25 | 23    |
| 26 | 23    |
Run Code Online (Sandbox Code Playgroud)

之后我可以很好地将此列与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;
Run Code Online (Sandbox Code Playgroud)

定义自定义 postgres 函数也是一个可以接受的解决方案。

感谢您的任何建议,

马蒂

kli*_*lin 5

在 Postgres 中,您可以创建自定义聚合。例子:

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[]
);
Run Code Online (Sandbox Code Playgroud)

Db<>小提琴。

阅读文档:用户定义的聚合