首页 > 解决方案 > 从 SELECT 返回的值生成列

问题描述

我有一个返回数据的查询,如下所示:

学生 课程 年级
一个学生 ENG-W05 100
一个学生 MAT-W05 85
一个学生 ENG-W06 100
b-学生 MAT-W05 90
b-学生 SCI-W05 75

数据按学生和课程分组。理想情况下,我希望将上述数据转换为以下数据:

学生 ENG-W05 MAT-W05 ENG-W06 SCI-W05
一个学生 100 85 100 无效的
b-学生 无效的 90 无效的 75

因此,转换后,每个学生只有一个记录,所有成绩(以及任何缺失的课程都被评为空)。

有没有人有任何想法?显然,如果我取出数据并将其转换为一种语言(如 Python),这很容易做到,但我希望通过 SQL 查询以所需格式获取数据。

另外,是否可以按字母顺序(升序)排列列?因此,最终输出将是:

学生 ENG-W05 ENG-W06 MAT-W05 SCI-W05
一个学生 100 100 85 无效的
b-学生 无效的 无效的 90 75

编辑:澄清一下,其中的值course是未知的。我提供的只是示例。因此,理想情况下,如果在第一个查询结果(第一个表)中发现更多课程值,它们仍将映射到最终结果中的列(无需更改查询)。实际上,我实际上有 >1kcourse列的不同值,所以我不能手动写出每个值。

标签: sqlpostgresqlselect

解决方案


演示:db<>小提琴

您可以为此使用条件聚合:

SELECT
    student,
    SUM(grade) FILTER (WHERE course = 'ENG-W05') as eng_w05, 
    SUM(grade) FILTER (WHERE course = 'MAT-W05') as mat_w05, 
    SUM(grade) FILTER (WHERE course = 'ENG-W06') as eng_w06, 
    SUM(grade) FILTER (WHERE course = 'SCI-W05') as sci_w05
FROM mytable
GROUP BY student

FILTER子句只允许聚合一些特定的记录。所以这个汇总了特定课程的所有记录。

找到正确的聚合函数可能很困难。这里SUM()可以完成这项工作,因为每组只有一个值。MAX()或者MIN()也会这样做。这取决于您的实际要求。如果每个组真的只有一个值,那没关系,您只需要进行任何聚合即可。


而不是FILTERPostgres 特定的子句,您可以使用更 SQL 标准的拟合CASE子句:

SELECT
    student,
    SUM(
       CASE 
           WHEN course = 'ENG-W05' THEN grade
       END
    ) AS eng_w05, 
    ...

推荐阅读