PostgreSQL 上的数据透视行

Pivot Row on PostgreSQL

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

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

这 return 如下:

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

我需要能够return这一行:

| 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 的新手,所以我不知道从哪里开始以及如何开始。

谢谢!

需要这个:

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,但它以相反的方式工作(从您想要的输出到您的输入)。


你有一个更短的选择,使用 arrays and unnest:

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 ;

你也可以在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)