具有多个值列的数据透视表/交叉表
Pivot / crosstab with more than one value column
我有一个生成以下结果集的视图:
CREATE TABLE foo
AS
SELECT client_id, asset_type, current_value, future_value
FROM ( VALUES
( 1, 0, 10 , 20 ),
( 1, 1, 5 , 10 ),
( 1, 2, 7 , 15 ),
( 2, 1, 0 , 2 ),
( 2, 2, 150, 300 )
) AS t(client_id, asset_type, current_value, future_value);
我需要将其转换成这样:
client_id a0_cur_val a0_fut_val a1_cur_val a1_fut_val ...
1 10 20 5 10
2 NULL NULL 0 2
如果我只使用 current_value
列,我知道如何使用交叉表来执行此操作。如何使用 current_value
和 future_value
在目标结果集中生成新列?如果我只是将 future_value
列添加到 crosstab(text)
查询中,它会抱怨 "invalid source data SQL statement".
我正在使用 PostgreSQL 9.3.6。
一种方法是使用复合类型:
CREATE TYPE i2 AS (a int, b int);
或者,对于临时使用(在会话期间注册类型):
CREATE TEMP TABLE i2 (a int, b int);
然后运行如你所知的交叉表并分解复合类型:
SELECT client_id
, (a0).a AS a0_cur_val, (a0).b AS a0_fut_val
, (a1).a AS a1_cur_val, (a1).b AS a1_fut_val
, (a2).a AS a2_cur_val, (a2).b AS a2_fut_val
FROM crosstab(
'SELECT client_id, asset_type, (current_value, future_value)::i2
FROM foo
ORDER BY 1,2'
,'SELECT * FROM generate_series(0,2)'
) AS ct (client_id int, a0 i2, a1 i2, a2 i2);
所有括号都是必需的!
crosstab()
的基础知识:
- PostgreSQL Crosstab Query
另一种选择是从两个交叉表查询中构建一个连接,您可以使用它来独立恢复两组值中的任何一个...含义:
select coalesce(cur.client_id, fut.client_id) client_id
, c0, f0, c1, f1, c2, f2
from
(select client_id, c0, c1, c2
from crosstab
('select client_id, asset_type, current_value
from foo
order by client_id, asset_type')
as sal1 (client_id int4, c0 int4 , c1 int4 , c2 int4)) cur
full outer join
(select client_id, f0, f1, f2
from crosstab
('select client_id, asset_type, future_value
from foo
order by client_id, asset_type')
as sal1 (client_id int4, f0 int4 , f1 int4 , f2 int4)) fut
on fut.client_id = cur.client_id
含义...在两个不同的交叉表查询中获取 current_value 和 future_value,然后将它们连接起来以获得连接查询中的结果
- 我对 client_id 使用了完整的外部连接和合并,以防任何客户端不能出现在包含当前值的第一个查询中,如果我们知道 current_value 始终存在我们可以使用左连接,如果同时需要当前值和未来值,那么内部连接就可以了
我有一个生成以下结果集的视图:
CREATE TABLE foo
AS
SELECT client_id, asset_type, current_value, future_value
FROM ( VALUES
( 1, 0, 10 , 20 ),
( 1, 1, 5 , 10 ),
( 1, 2, 7 , 15 ),
( 2, 1, 0 , 2 ),
( 2, 2, 150, 300 )
) AS t(client_id, asset_type, current_value, future_value);
我需要将其转换成这样:
client_id a0_cur_val a0_fut_val a1_cur_val a1_fut_val ...
1 10 20 5 10
2 NULL NULL 0 2
如果我只使用 current_value
列,我知道如何使用交叉表来执行此操作。如何使用 current_value
和 future_value
在目标结果集中生成新列?如果我只是将 future_value
列添加到 crosstab(text)
查询中,它会抱怨 "invalid source data SQL statement".
我正在使用 PostgreSQL 9.3.6。
一种方法是使用复合类型:
CREATE TYPE i2 AS (a int, b int);
或者,对于临时使用(在会话期间注册类型):
CREATE TEMP TABLE i2 (a int, b int);
然后运行如你所知的交叉表并分解复合类型:
SELECT client_id
, (a0).a AS a0_cur_val, (a0).b AS a0_fut_val
, (a1).a AS a1_cur_val, (a1).b AS a1_fut_val
, (a2).a AS a2_cur_val, (a2).b AS a2_fut_val
FROM crosstab(
'SELECT client_id, asset_type, (current_value, future_value)::i2
FROM foo
ORDER BY 1,2'
,'SELECT * FROM generate_series(0,2)'
) AS ct (client_id int, a0 i2, a1 i2, a2 i2);
所有括号都是必需的!
crosstab()
的基础知识:
- PostgreSQL Crosstab Query
另一种选择是从两个交叉表查询中构建一个连接,您可以使用它来独立恢复两组值中的任何一个...含义:
select coalesce(cur.client_id, fut.client_id) client_id
, c0, f0, c1, f1, c2, f2
from
(select client_id, c0, c1, c2
from crosstab
('select client_id, asset_type, current_value
from foo
order by client_id, asset_type')
as sal1 (client_id int4, c0 int4 , c1 int4 , c2 int4)) cur
full outer join
(select client_id, f0, f1, f2
from crosstab
('select client_id, asset_type, future_value
from foo
order by client_id, asset_type')
as sal1 (client_id int4, f0 int4 , f1 int4 , f2 int4)) fut
on fut.client_id = cur.client_id
含义...在两个不同的交叉表查询中获取 current_value 和 future_value,然后将它们连接起来以获得连接查询中的结果
- 我对 client_id 使用了完整的外部连接和合并,以防任何客户端不能出现在包含当前值的第一个查询中,如果我们知道 current_value 始终存在我们可以使用左连接,如果同时需要当前值和未来值,那么内部连接就可以了