我已尝试过很多方法在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)
答案 0 :(得分:0)
crosstab()
如果您不熟悉交叉表(),请先阅读:
这里有两个复杂因素:
涉及的数据类型是不均匀的。 (使我想要检查您的数据库设计。)共同点是将相关列转换为text
。
你正在将交叉制表混合在一起(有时候称为“unpivot”)。
建立在稍微简化的表格上:
CREATE TEMP TABLE view1(
id int
, a int
, b text
, c text
);
我看到两条基本路线:
首先将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()
电话。另外,您可能希望将a1
和a2
投回到bigint
外的int
(或仅SELECT
?):
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);
VOILÀ。
要获得更加动态的解决方案,请结合以下答案:
分别为a
,b
和c
运行交叉表,并加入id
上的派生表。