当我期望多行时,Postgres中的交叉表函数返回一行输出

Ste*_*ori 5 sql postgresql pivot-table crosstab window-functions

我目前有一个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
Run Code Online (Sandbox Code Playgroud)

我想创建下表:

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
Run Code Online (Sandbox Code Playgroud)

tablefunc扩展已经在我的Postgres数据库中创建.我目前正在尝试使用该crosstab()功能来完成枢轴.但是,我得到的表格如下所示:

id    scenario    period    1    2   3    4 
2        1          1       1    1   1    1
Run Code Online (Sandbox Code Playgroud)

我试过的查询:

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);
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 5

此查询生成您想要的输出:

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);
Run Code Online (Sandbox Code Playgroud)

两个特殊困难:

  1. 您还没有row_name的唯一列。我用来row_number()生成代理键:rn。我将其从外部移除SELECT以符合您想要的结果。
    您尝试的方式id被视为 row_name 所有输入行都聚合到单个输出行中。

  2. 您需要在结果中添加额外的列(scenario和),这些列必须位于row_name之后、category之前。您必须列出两次才能额外获得原始列 - 似乎是多余的。periodperiod

基本:

与此特定案例相关:


通常,您会有这样的查询:

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);
Run Code Online (Sandbox Code Playgroud)

输出如下:

id   scenario   p1   p2   p3   p4
2    1          1    1    1    1
2    2          1    1    1    1
2    3          1    1    1    1
Run Code Online (Sandbox Code Playgroud)

请注意使用rank()代替row_number()将相同的组合组合(id, scenario)在一起。
如果计数不是全部,则结果更有意义1