当我期望多行时,Postgres 中的交叉表函数返回一行输出
Crosstab function in Postgres returning a one row output when I expect multiple rows
我目前有一个 table m
格式如下:
id scenario period ct
2 1 1 1
2 1 2 1
2 1 3 1
2 1 4 1
2 2 1 1
2 2 2 1
2 2 3 1
2 2 4 1
2 3 1 1
2 3 2 1
2 3 3 1
2 3 4 1
我想创建以下 table:
id scenario period 1 2 3 4
2 1 1 1
2 1 2 1
2 1 3 1
2 1 4 1
2 2 1 1
2 2 2 1
2 2 3 1
2 2 4 1
2 3 1 1
2 3 2 1
2 3 3 1
2 3 4 1
我的 Postgres 数据库中已经创建了 tablefunc 扩展。我目前正在尝试使用 crosstab()
函数来完成数据透视。但是,我得到的 table 如下所示:
id scenario period 1 2 3 4
2 1 1 1 1 1 1
我试过的查询:
SELECT * FROM crosstab(
'SELECT id, scenario, period, ct FROM m
ORDER BY 1',
'SELECT DISTINCT period FROM m
ORDER BY 1')
AS (id, scenario, period, 1, 2, 3, 4);
此查询生成您想要的输出:
SELECT id, scenario, period, p1, p2, p3, p4 -- all except aux column rn
FROM crosstab(
'SELECT row_number() OVER (ORDER BY id, scenario, period)::int AS rn
, id, scenario, period, period, ct
FROM m
ORDER BY 1'
, 'VALUES (1), (2), (3), (4)'
) AS (rn int, id int, scenario int, period int, p1 int, p2 int, p3 int, p4 int);
两个特殊困难:
您还没有 row_name 的唯一列。我使用 row_number()
生成代理键:rn
。我从外部 SELECT
中删除了它以匹配您想要的结果。
按照您尝试的方式,id
被视为 row_name 并且所有输入行都聚合到单个输出行中。
您想要在结果中添加额外的列(scenario
和 period
),这些列必须在 row_name[=59= 之后] 和 类别 之前。您必须列出 period
两次 才能额外获得原始列 - 看起来是多余的。
基础知识:
- PostgreSQL Crosstab Query
与此特定案例相关:
- Pivot on Multiple Columns using Tablefunc
通常,您会有这样的查询:
SELECT id, scenario, p1, p2, p3, p4 -- all except aux column rn
FROM crosstab(
'SELECT rank() OVER (ORDER BY id, scenario)::int AS rn
, id, scenario, period, ct
FROM m
ORDER BY 1'
, 'VALUES (1), (2), (3), (4)'
) AS (rn int, id int, scenario int, p1 int, p2 int, p3 int, p4 int);
输出如下:
id scenario p1 p2 p3 p4
2 1 1 1 1 1
2 2 1 1 1 1
2 3 1 1 1 1
请注意使用 rank()
而不是 row_number()
将 (id, scenario)
的相同组合组合在一起。
如果计数不全是 1
.
,则结果更有意义
我目前有一个 table m
格式如下:
id scenario period ct
2 1 1 1
2 1 2 1
2 1 3 1
2 1 4 1
2 2 1 1
2 2 2 1
2 2 3 1
2 2 4 1
2 3 1 1
2 3 2 1
2 3 3 1
2 3 4 1
我想创建以下 table:
id scenario period 1 2 3 4
2 1 1 1
2 1 2 1
2 1 3 1
2 1 4 1
2 2 1 1
2 2 2 1
2 2 3 1
2 2 4 1
2 3 1 1
2 3 2 1
2 3 3 1
2 3 4 1
我的 Postgres 数据库中已经创建了 tablefunc 扩展。我目前正在尝试使用 crosstab()
函数来完成数据透视。但是,我得到的 table 如下所示:
id scenario period 1 2 3 4
2 1 1 1 1 1 1
我试过的查询:
SELECT * FROM crosstab(
'SELECT id, scenario, period, ct FROM m
ORDER BY 1',
'SELECT DISTINCT period FROM m
ORDER BY 1')
AS (id, scenario, period, 1, 2, 3, 4);
此查询生成您想要的输出:
SELECT id, scenario, period, p1, p2, p3, p4 -- all except aux column rn
FROM crosstab(
'SELECT row_number() OVER (ORDER BY id, scenario, period)::int AS rn
, id, scenario, period, period, ct
FROM m
ORDER BY 1'
, 'VALUES (1), (2), (3), (4)'
) AS (rn int, id int, scenario int, period int, p1 int, p2 int, p3 int, p4 int);
两个特殊困难:
您还没有 row_name 的唯一列。我使用
row_number()
生成代理键:rn
。我从外部SELECT
中删除了它以匹配您想要的结果。
按照您尝试的方式,id
被视为 row_name 并且所有输入行都聚合到单个输出行中。您想要在结果中添加额外的列(
scenario
和period
),这些列必须在 row_name[=59= 之后] 和 类别 之前。您必须列出period
两次 才能额外获得原始列 - 看起来是多余的。
基础知识:
- PostgreSQL Crosstab Query
与此特定案例相关:
- Pivot on Multiple Columns using Tablefunc
通常,您会有这样的查询:
SELECT id, scenario, p1, p2, p3, p4 -- all except aux column rn
FROM crosstab(
'SELECT rank() OVER (ORDER BY id, scenario)::int AS rn
, id, scenario, period, ct
FROM m
ORDER BY 1'
, 'VALUES (1), (2), (3), (4)'
) AS (rn int, id int, scenario int, p1 int, p2 int, p3 int, p4 int);
输出如下:
id scenario p1 p2 p3 p4
2 1 1 1 1 1
2 2 1 1 1 1
2 3 1 1 1 1
请注意使用 rank()
而不是 row_number()
将 (id, scenario)
的相同组合组合在一起。
如果计数不全是 1
.