Postgres - SQL 查询从多对多映射中提取类似交叉表的功能

发布于 2025-01-14 16:42:34 字数 1422 浏览 1 评论 0原文

我在 PostgreSQL 数据库中有一个由 StudentSubject 组成的数据集。关系类似于:

学生:
身份证号,
姓名,
...

Student ID  | Name      | ... 
1 | Ramesh | ...
2 | Suresh | ...

主题:
身份证号,
姓名,
...

Subject ID  | Name      | ...
1 | Maths | ...
2 | Science | ...

Student_Subject:
身份证号,
学生 ID,
subject_id,
...

第三个表,正如人们想象的那样,它是一种表示多对多映射的形式。假设一个学生选择了 3 个科目,那么在 Student_subject 表中他将有 3 个针对其 ID 的映射。

学生可以选择的科目数量没有限制,可以是 0 到 10 之间的任何值。

我需要创建一个 SQL 查询,它将获取以下格式的记录:

Student ID  | Student Name  | Maths         | Science       | ...   | History
1           | Ramesh        | Y             | N             | ...   | Y
2           | Suresh        | N             | Y             | ...   | Y

科目名称可以硬编码为列别名,即美好的。

有人可以建议如何实现这一点吗?

我尝试使用 case when 技术:

    select 
        stud.name,
        (case when sub.name = 'Maths' then 'Y' else 'N' end) "Maths",
        (case when sub.name = 'Science' then 'Y' else 'N' end) "Science", 
        ...
    from student stud
        inner join student_subject s_s on s_s.student_id = stud.id
        inner join subject sub on sub.id = s_s.student_id
    ;

但这样我就不会为每个学生获取一行。如果学生选择了 3 个科目,我会得到 3 个不同的行,每行的每个科目都有一个 Y 值。

I have a data-set consisting of Student and Subject in a PostgreSQL Database. The relations look something like:

Student:
id,
name,
...

Student ID  | Name      | ... 
1 | Ramesh | ...
2 | Suresh | ...

Subject:
id,
name,
...

Subject ID  | Name      | ...
1 | Maths | ...
2 | Science | ...

Student_Subject:
id,
student_id,
subject_id,
...

The third table, as one could imagine, it's a form of representing many-to-many mapping. Suppose a student has selected 3 subjects, he will have 3 mappings against his ID in the student_subject table.

There is no restriction on the number of subjects that a student may select it could be anything between 0 and 10.

I need to create a single SQL query, that will fetch records in this format:

Student ID  | Student Name  | Maths         | Science       | ...   | History
1           | Ramesh        | Y             | N             | ...   | Y
2           | Suresh        | N             | Y             | ...   | Y

The Subject names could be hardcoded as column aliases that's fine.

Can someone pls suggest how this can be achieved?

I tried using the case when technique as:

    select 
        stud.name,
        (case when sub.name = 'Maths' then 'Y' else 'N' end) "Maths",
        (case when sub.name = 'Science' then 'Y' else 'N' end) "Science", 
        ...
    from student stud
        inner join student_subject s_s on s_s.student_id = stud.id
        inner join subject sub on sub.id = s_s.student_id
    ;

But this way I'm not getting one row per student. If the student has selected 3 subjects, I'm getting 3 different rows with one Y value against each of the subjects on each row.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

日暮斜阳 2025-01-21 16:42:34

基于固定科目列表的静态解决方案:

您必须按学生对结果行进行分组,以便为​​每个学生获取一行,并且对于每个组,使用返回 True 的 bool_or() 聚合函数当组中至少一行返回 True 时:

select 
    stud.name,
    bool_or(case when sub.name = 'Maths' then True else False end) "Maths",
    bool_or(case when sub.name = 'Science' then True else False end) "Science", 
    ...
from student stud
    inner join student_subject s_s on s_s.student_id = stud.id
    inner join subject sub on sub.id = s_s.student_id
group by stud.name

当主题列表可能演变时动态解决方案:

请参阅 如何动态添加列PostgresSQL 选择?

Static solution based on a fix list of subjects :

You have to group the resulting rows by student so that to get one row per student, and for each group, use the bool_or() aggregate function which returns True when at least on row in the group returns True :

select 
    stud.name,
    bool_or(case when sub.name = 'Maths' then True else False end) "Maths",
    bool_or(case when sub.name = 'Science' then True else False end) "Science", 
    ...
from student stud
    inner join student_subject s_s on s_s.student_id = stud.id
    inner join subject sub on sub.id = s_s.student_id
group by stud.name

Dynamic solution when the list of subjects may evolve :

see How to dynamically add columns in PostgresSQL select?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文