我有五(5)个表:学生,科目,期间_一,期间_two和期间_三。我正在执行左连接以从这五个表中选择值:
学生表(学生)
student_id | Name
--------------|-------
1 |John
2 |Peter
3 |Flomo
主题表(科目)
subject_id |SubjectName
-----------------|-------
math101 |Mathematics
eng201 |English
lang303 |Language Arts
期间一个表(period_one)
id|student_id |subject_id| score
--------------|----------|-----
1 |1 | math101 |99
2 |2 | eng201 |88
3 |3 | lang303 |77
期间二表(period_two)
id|student_id |subject_id| score
--------------|----------|-----
1 |1 | math101 |100
2 |2 | eng201 |60
3 |3 | lang303 |65
期间三表(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和periodThree)。我查看了问题(https://www.w3schools.com/sql/sql_join_left.asp),并确认这不是最好的做事方式。
我做了一些改变
所以,我将查询更新为这样( 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
WHERE students.student_id = 3 OR period_one.student_id = 3 OR period_two.student_id = 3 OR period_three.student_id = 3
这非常有效,因为学生表是所有句号表引用的主表。如果学生ID不在period_one和period_two表中,而是在period_there中,则该表的studentId,subjectId和score将返回。
然后又出现问题
在我更新我的代码之前,我正在按照我想要的方式显示记录,但是并没有按照需要的方式获取/检索记录。这就是促使我改变查询的原因,因为我发现这是问题所在。
现在,基于我的第一个查询( Query1 ),我从select语句中的各个表中选择了subject_id。当我显示记录时,我传递了subject_id从查询返回到获取该id的主题名称的函数。这就是我显示结果的方式:
如果学生id在表中分配给from子句,则此方法有效,否则不返回任何内容。这就是我改变代码的原因。
但是现在我已将代码更改为( Query2 )我无法显示主题ID及其名称,因为它不在学生表中。以下是我如何显示记录的要点:https://gist.github.com/nathansiafa/e9d22791800d4ba3a00e2b98de52baec
有没有办法可以让它更好地运作?将欣赏建议和反馈。谢谢!
答案 0 :(得分:0)
对我来说问题是数据不是正常形式导致问题。由于主题和分数基本上是相同的结构,没有句点符号,我首先将所有三个表合并在一起并创建一个" Period"结果中的列。
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 to" Pivot"数据允许我们显示得分和主题。
如果我们需要实际的主题名称,那么根据subject_ID密钥左键加入主题表就可以了。
我假设学生只能在每个期间表中出现一次。
答案 1 :(得分:0)
您似乎从技术/编程角度过度思考,而不是关注您想要拥有的数据的语义含义。
您真正想要的是科目的列表,以及特定学生的科目的分数。学生在这里有点正交,因为正在建立一个表,但学生不是该表的一部分。
因此,步骤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;