Postgresql 中的自定义序列或 windows 函数

Custom sequence or windows function in Postgresql

我有一个巨大的 table 看起来像这样

Group | Code | Value
------|------|------
G1    |0     |V1
G1    |2     |V2
G1    |2     |V3     
G1    |1     |V4
G1    |2     |V5
G1    |2     |V6

G2    |0     |V7
G2    |1     |V8
G2    |1     |V9     
G2    |2     |V10
G2    |2     |V11
G2    |2     |V12
G2    |2     |V13

我需要像这样生成一个table

Group | Code | Value
------|------|------
G1    |0     |V1
G1    |2     |V2+V3
G1    |1     |V4
G1    |2     |V5+V6

G2    |0     |V7
G2    |1     |V8
G2    |1     |V9     
G2    |2     |V10+V11
G2    |2     |V12+V13

code = 2 总是成对出现,我需要将 code = 2 的两个连续值相加。关于如何使用 SQL 语句而不是存储过程的任何想法?任何可以帮助我做到这一点的特殊功能。我正在尝试 Postgres 9.6 谢谢。

我假设您希望行按 Value 列的数字部分排序。如果我们将 t 称为 table,这里有一个使用 window 函数执行您想要的操作的查询:

SELECT "group", code, string_agg(value, '+')
FROM
   (SELECT *, (row_number() OVER (PARTITION BY "group", code ORDER BY n) - 1) / CASE code WHEN 2 THEN 2 ELSE 1 END AS code_group
    FROM (SELECT *,substr(value,2)::integer AS n FROM t) t1
   ) t2
GROUP BY "group", code, code_group
ORDER BY min(n);

我们的想法是首先提取(在子查询中)value 的数字部分,以便我们稍后可以将其用作排序键。然后我们使用下面的复数表达式:

(row_number() OVER (PARTITION BY "group", code ORDER BY n) - 1) / CASE code WHEN 2 THEN 2 ELSE 1 END

这基本上为每组行(按 groupcode 分组)分配了一个从 0 开始递增的数字。所以第一行是 0,下一行是 1,依此类推.但有一个例外。如果 code 是 2,那么我们使用以下编号方案:0, 0, 1, 1, 2, 2, .... 这是通过将行号除以 2 来实现的。我称这个数字为code_group。在最后一步中,我们按 groupcode(和之前一样)和 code_group 分组,以便 code=2 的连续行对合并为一个。

select *
from (
    select 
        grp, code, 
        case when code = 2 then
            case when rn & 1 = 1 then null
            else concat(lag(value) over w, '+', value)
            end
        else value
        end as value
    from (
        select *, row_number() over w rn
        from a_table
        window w as (partition by code order by grp, code)
        ) s
    window w as (order by grp, code, rn)
    ) s
where value notnull
order by grp, code

步骤:

  • 按组和代码在分区上添加行号
    • 如果代码 = 2 且其行号为奇数,则 select null as value
    • 如果代码 = 2 且其行号为偶数,则将其和之前的值连接为值
    • if code <> 2 then just select value
  • 跳过具有空值的行。