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
这基本上为每组行(按 group
、code
分组)分配了一个从 0 开始递增的数字。所以第一行是 0,下一行是 1,依此类推.但有一个例外。如果 code
是 2,那么我们使用以下编号方案:0, 0, 1, 1, 2, 2, .... 这是通过将行号除以 2 来实现的。我称这个数字为code_group
。在最后一步中,我们按 group
、code
(和之前一样)和 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
- 跳过具有空值的行。
我有一个巨大的 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
这基本上为每组行(按 group
、code
分组)分配了一个从 0 开始递增的数字。所以第一行是 0,下一行是 1,依此类推.但有一个例外。如果 code
是 2,那么我们使用以下编号方案:0, 0, 1, 1, 2, 2, .... 这是通过将行号除以 2 来实现的。我称这个数字为code_group
。在最后一步中,我们按 group
、code
(和之前一样)和 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
- 跳过具有空值的行。