将某些行更改为列
Posted
技术标签:
【中文标题】将某些行更改为列【英文标题】:Change some of the rows to columns 【发布时间】:2014-09-04 16:20:22 【问题描述】:我已经尝试了很多方法在 Postgres 中按列“转置”行,但我仍然做不到。 给定 Postgres 视图中的一组数据,如下所示:
查看1
ID|A_|B_|C_
--+--+--+--
01|25|AA|1C
02|50|BB|1C
02|12|AA|2C
03|27|BB|2C
03|87|AA|3C
我希望能够对此结果进行查询:
ID| A_1| B_1| C_1| A_2| B_2| C_2
--+----+----+----+----+----+----
01| 25 | AA | 1C | __ | __ | __
02| 50 | BB | 1C | 12 | AA | 2C
03| 27 | BB | 2C | 87 | AA | 3C
这甚至可以尝试在 Postgres 中进行吗?我正在尝试做这样的事情
select * from crosstab(
$$select id, a_, b_, c_, rn
from (
select v.id, v.a_, v.b_, v.c_, row_number() over (partition by v.id order by v.id desc nulls last) as rn
from view1 v
) sub
order by id
$$
, 'values (1), (2), (3)'
) as t (id varchar, a_1 bigint, b_1 varchar, c_1 varchar, a_2 varchar, b_2 varchar, c_2 varchar)
【问题讨论】:
您能展示一下到目前为止您尝试过的内容吗? 这在任何数据库中都是可能的,但如上所述,您需要展示一些工作原理order by v.id
在您的窗口子句中没有意义。您如何确定每组相同ID
中的“第一”和“第二”值?
【参考方案1】:
crosstab()
的基础知识
如果您不熟悉 crosstab(),请先阅读以下内容:
PostgreSQL Crosstab Query特殊难度
这里有两个并发症:
涉及的数据类型是不均匀的。 (让我想检查您的数据库设计。)共同点是将涉及的列转换为text
。
您将交叉制表与相反的(有时称为“unpivot”)混合在一起。
建立在一个稍微简化的表格上:
CREATE TEMP TABLE view1(
id int
, a int
, b text
, c text
);
我看到了两条基本路线:
路线 1
首先将 a、b、c 还原为这种形式。并行使用 Postgres 特定的 unnest()
。此处说明:
SELECT id
, unnest('a,b,c'::text[]) || rn AS key
, unnest(ARRAY[a::text, b::text, c::text]) AS val
FROM (
SELECT *, row_number() OVER (PARTITION BY id) AS rn -- ORDER BY ??
FROM view1
) v;
假设每个 id 值只能最多两行。您如何确定“第一”和“第二”是未定义的。结果(使用您的测试数据):
id key val
1 a1 25
1 b1 AA
1 c1 1C
2 a1 50
2 b1 BB
2 c1 1C
2 a2 12
2 b2 AA
2 c2 2C
3 a1 27
3 b1 BB
3 c1 2C
3 a2 87
3 b2 AA
3 c2 3C
SQL Fiddle.
其余的在 sqlfiddle.com 上是不可能的,因为没有安装附加模块 tablefunc
。
将此查询提供给标准的crosstab()
调用。另外,您可能想在外部SELECT
中将a1
和a2
转换回bigint
(或只是int
?):
SELECT id, a1::bigint, b1, c1, a2::bigint, b2, c2 -- or just SELECT *
FROM crosstab(
$$
SELECT id
,unnest('a,b,c'::text[]) || rn
,unnest(ARRAY[a::text, b::text, c::text])
FROM (
SELECT *, row_number() OVER (PARTITION BY id) AS rn
FROM view1
) v
$$
, $$SELECT unnest('a1,b1,c1,a2,b2,c2'::text[])$$
) AS t (id varchar, a1 text, b1 text, c1 text, a2 text, b2 text, c2 text);
瞧。 要获得更动态的解决方案,请结合以下答案:
How to unpivot a table in PostgreSQL Dynamic alternative to pivot with CASE and GROUP BY路线 2
分别为a
、b
和c
运行交叉表,并在id
上连接派生表。
【讨论】:
非常感谢您的帮助!我会用它以上是关于将某些行更改为列的主要内容,如果未能解决你的问题,请参考以下文章