PostgreSQL上的Pivot Row

时间:2017-01-05 20:40:31

标签: postgresql pivot pivot-table

我有一个返回整行的查询,我需要将此结果转换为新表。

SELECT id_no, stud_name, group_no, class_1, class_2, class_3, class_4 FROM tbl_stud_class

返回以下内容:

| id_no | stud_name | group_no | class_1 | class_2 | class_3 | class 4 |
| 1     | John Doe  | A11      | 84      | 60      | 80      | 79      |

我需要能够将此行返回为:

| id_no | stud_name | group_no | class   | grade |
| 1     | John Doe  | A11      | class_1 | 84    |
| 1     | John Doe  | A11      | class_2 | 60    |
| 1     | John Doe  | A11      | class_3 | 80    |
| 1     | John Doe  | A11      | class_4 | 79    |

有人能指点我这样做吗? 我对PostgreSQL很新,所以我不知道在哪里以及如何开始。

谢谢!

2 个答案:

答案 0 :(得分:2)

您也可以在postgresql 9.3 +

中使用LATERAL
SELECT id_no, stud_name, group_no, class, grade
FROM   tbl_stud_class 
       CROSS JOIN LATERAL ( VALUES
                     ('class_1', class_1),
                     ('class_2', class_2),
                     ('class_3', class_3),
                     ('class_4', class_4)
            ) l(class, grade)

答案 1 :(得分:0)

需要这个:

WITH tbl_stud_class
     (id_no, stud_name, group_no, class_1, class_2, class_3, class_4) AS
(
    VALUES
      (1, 'John Doe', 'All', 84, 60, 80, 79),
      (2, 'Aberel Dalton', 'Some', 75, 32, NULL, 80)
)

SELECT
    id_no, stud_name, group_no, 'class_1' AS class, class_1 AS grade
FROM
    tbl_stud_class
WHERE 
    class_1 IS NOT NULL
UNION
SELECT
    id_no, stud_name, group_no, 'class_2' AS class, class_2 AS grade 
FROM
    tbl_stud_class
WHERE 
    class_2 IS NOT NULL
UNION
SELECT
    id_no, stud_name, group_no, 'class_3' AS class, class_3 AS grade
FROM
    tbl_stud_class
WHERE 
    class_3 IS NOT NULL
UNION
SELECT
    id_no, stud_name, group_no, 'class_4' AS class, class_4 AS grade
FROM
    tbl_stud_class 
WHERE 
    class_4 IS NOT NULL 
ORDER BY
    id_no, class ;

AFAIK,无法以自动方式执行此操作。 PostgreSQL有crosstab函数,它可以执行PIVOT,但它可以反过来(从您想要的输出到输入)。

您可以使用arraysunnest来缩短替代选择:

WITH tbl_stud_class
     (id_no, stud_name, group_no, class_1, class_2, class_3, class_4) AS
(
    VALUES
      (1, 'John Doe', 'All', 84, 60, 80, 79),
      (2, 'Aberel Dalton', 'Some', 75, 32, NULL, 80)
)

SELECT
    *
FROM
(
    SELECT
        id_no, stud_name, group_no, 
        unnest(ARRAY['class_1', 'class_2', 'class_3', 'class_4']) AS class,
        unnest(ARRAY[ class_1,   class_2,   class_3,   class_4 ]) AS grade
    FROM
        tbl_stud_class
) AS s0        
WHERE
    grade is not null 
ORDER BY
    id_no, class ;