首页 文章

如果值不存在,如何在左连接字段上返回null

提问于
浏览
1

我有五(5)个表:学生,科目,period_one,period_two和period_three . 我正在执行左连接以从这五个表中选择值:

Students Table (students)

student_id    | Name
  --------------|-------
  1             |John
  2             |Peter
  3             |Flomo

Subjects Table (subjects)

subject_id       |SubjectName
  -----------------|-------
  math101          |Mathematics
  eng201           |English
  lang303          |Language Arts

Period One Table (period_one)

id|student_id |subject_id| score
  --------------|----------|-----
  1 |1          | math101  |99
  2 |2          | eng201   |88
  3 |3          | lang303  |77

Period Two Table (period_two)

id|student_id |subject_id| score
  --------------|----------|-----
  1 |1          | math101  |100
  2 |2          | eng201   |60
  3 |3          | lang303  |65

Period Three Table (period_three)

id|student_id |subject_id| score
  --------------|----------|-----
  1 |1          | math101  |71
  2 |2          | eng201   |51
  3 |3          | lang303  |71

这是我用来检索记录的查询 Query1

SELECT period_one.student_id, period_one.subject_id, period_one.score, period_two.score,period_three.score

from period_one

LEFT JOIN period_two
ON period_one.subject_id = period_two.subject_id
AND period_one.student_id = period_two.student_id

LEFT JOIN period_three 
on period_one.subject_id = period_three.subject_id
AND period_one.student_id = period_three.student_id

WHERE period_one.student_id = 10

上面代码的问题是,如果我正在查找的学生ID不在第一个表(periodOne)中,左连接正在应用于查询,则返回null,即使该学生的记录在其他表中(periodTwo)和期间三) . 我查看了这个问题(https://www.w3schools.com/sql/sql_join_left.asp),并证实这不是最好的做事方式 .

I THEN MADE SOME CHANGES

所以,我更新了我的查询,看起来像这样( Query2 ):

SELECT students.student_id, period_one.score, period_one.subject_id, 
period_two.score, period_two.subject_id, period_three.score, 
period_three.subject_id
from students

LEFT JOIN period_one
ON students.student_id = period_one.student_id

LEFT JOIN period_two
ON students.student_id = period_two.student_id

LEFT JOIN period_three 
ON students.student_id = period_three.student_id

在哪里students.student_id = 3 OR period_one.student_id = 3 OR period_two.student_id = 3 OR period_three.student_id = 3

这完美地工作,因为学生表是所有期间表 are referencing 的主表 . 如果学生ID不在period_one和period_two表中,而是在period_there中,则返回该表的studentId,subjectId和score .

THEN ANOTHER PROBLEM POPS OUT

在我更新代码之前,我正在按照我想要的方式显示记录,但是没有按照需要的方式获取/检索记录 . 这就是促使我改变查询的原因,因为我发现这是问题所在 .

现在,基于我的第一个查询( Query1 ),我从select语句中的各个表中选择了subject_id . 当我显示记录时,我传递了subject_id从查询返回到获取该id的主题名称的函数 . 这就是我显示结果的方式:

enter image description here

如果学生id在表中分配给from子句,则此方法有效,否则不返回任何内容 . 这就是我改变代码的原因 .

但现在我已将代码更改为( Query2 )我'm unable to display the subject id and its name because it is not within the students table. Here is a gist on how I' m显示我的记录:https://gist.github.com/nathansiafa/e9d22791800d4ba3a00e2b98de52baec

有没有办法让它更好地运作?将欣赏建议和反馈 . 谢谢!

2 回答

  • 0

    看起来你从技术/编程的角度来思考一点,而不是关注你想拥有的数据的语义 .

    你真正想要的是 subjects 的列表,以及特定 student 的那些主题的 scores . 学生在这里有点正交,因为正在 Build 一个表,但学生不是该表的一部分 .

    因此,第1步将选择我们想要的数据 - 主题及其得分:

    SELECT s.subject_id, s.subject_name, p1.score period_1_score, p2.score period_2_score, p3.score period_3_score 
    FROM subject s
    LEFT JOIN period_one p1 ON p1.subject_id = s.subject_id 
        AND p1.student_id = 10
    LEFT JOIN period_two p2 ON p2.subject_id = s.subject_id 
        AND p2.student_id = 10
    LEFT JOIN period_three p3 ON p3.subject_id = s.subject_id 
        AND p3.student_id = 10
    ORDER BY s.subject_name;
    

    这将为您提供所需的表格数据 - 首先是主题,然后是它们存在的分数 .

    现在,如果你坚持在同一个查询中加载学生数据(我建议你只有一个单独的查询 SELECT * FROM student WHERE student_id=10 ),那么你可以将它连接在一起:

    SELECT s.subject_id, s.subject_name, p1.score period_1_score, p2.score period_2_score, p3.score period_3_score, st.name student_name
    FROM subject s
    LEFT JOIN period_one p1 ON p1.subject_id = s.subject_id 
        AND p1.student_id = 10
    LEFT JOIN period_two p2 ON p2.subject_id = s.subject_id 
        AND p2.student_id = 10
    LEFT JOIN period_three p3 ON p3.subject_id = s.subject_id 
        AND p3.student_id = 10
    LEFT JOIN student st ON st.student_id = 10
    ORDER BY s.subject_name;
    
  • 0

    对我来说问题是数据不是正常形式导致你的问题 . 由于主题和分数基本上是相同的结构,没有句点符号,我首先将所有三个表合并在一起并在结果中创建“句点”列 .

    SELECT X.*, 1 as Period from Period_one X
    UNION ALL 
    SELECT Y.*, 2 as Period FROM PERIOD_TWO Y
    UNION ALL
    SELECT Z.*, 3 as Period FROM PERIOD_THREE Z
    

    然后我使用内联视图女巫成为左连接的一部分,所以我们没有在第一次查询的某些时期错过学生的问题 .

    SELECT Student_ID
         , max(Case when Period = 1 then B.Subject_ID end) as Period_one_Subject
         , max(case when Period = 1 then B.Score end) as Period_one_Score 
         , max(Case when Period = 2 then B.Subject_ID) end as Period_Two_Subject
         , max(case when Period = 2 then B.Score end as Period_two_Score 
         , max(Case when Period = 3 then B.Subject_ID end) as Period_Three_Subject
         , max(case when Period = 3 then B.Score end) as Period_Three_Score 
    FROM STUDENTS S
    LEFT JOIN (SELECT Y.*, 1 as Period from Period_one X
               UNION ALL 
               SELECT X.*, 2 as Period FROM PERIOD_TWO Y
               UNION ALL
               SELECT Z.*, 3 as Period FROM PERIOD_THREE Z) B
     on S.Student_ID = B.Student_ID
    GROUP BY Student_ID
    

    我们使用max和group by student来“旋转”数据,以便我们显示得分和主题 .

    如果我们需要实际的主题名称,那么根据subject_ID键左键加入主题表是一件简单的事情 .

    我假设学生只能在每个期间表中出现一次 .

相关问题