同一个表上有多个LEFT JOIN语句

时间:2015-10-28 11:19:33

标签: mysql sql join left-join

我正在尝试多次在同一个表上LEFT JOIN,以获取特定主题的所有值。它像我想象的那样工作,见:http://sqlfiddle.com/#!9/9cda67/4

但是,使用上述小提琴,数据库会为每个不同的课程返回一行。我想使用GROUP BY PersonID对它们进行分组,但是对于所有其他列,它只会取第一个值(数学为6)和(null)值。请参阅:http://sqlfiddle.com/#!9/9cda67/5

我需要更改哪些内容,以便每个人获得一行,并将所有成绩填入各自的列(如果可用)?

1 个答案:

答案 0 :(得分:2)

MySQL允许您在SELECT中包含不在GROUP BY中的列。这实际上违反了ANSI标准,并且不受任何其他数据库的支持(尽管在某些情况下ANSI标准允许它)。结果是输出中单行的不确定值。

解决方案是聚合函数:

SELECT p.id AS PersonID, p.name AS PersonName,
       max(pc1.grade) AS Math,
       max(pc2.grade) AS Chemistry,
       max(pc3.grade) AS Physics
FROM Person p LEFT JOIN
     Person_Course pc
     on p.id = pc.user_id LEFT JOIN
     Course c on c.id = pc.course_id LEFT JOIN
     Person_Course pc1
     on pc1.id = pc.id AND pc1.course_id = 1 LEFT JOIN 
     Person_Course pc2
     on pc2.id = pc.id AND pc2.course_id = 2 LEFT JOIN 
     Person_Course pc3
     on pc3.id = pc.id AND pc3.course_id = 3 
GROUP BY PersonID;

如果人们可以多次参加同一课程,您可能需要group_concat()。另外,不要对列名使用单引号。仅将它们用于字符串和日期常量。

将课程ID硬连接到代码中似乎是一个坏主意。我会更简单地使用条件聚合来写这个:

SELECT p.id AS PersonID, p.name AS PersonName,
       max(case when c.name = 'Math' then pc.grade end) AS Math,
       max(case when c.name = 'Chemistry' then pc.grade end) AS Chemistry,
       max(case when c.name = 'Physics' then pc.grade end) AS Physics
FROM Person p LEFT JOIN
     Person_Course pc
     on p.id = pc.user_id LEFT JOIN
     Course c
     on c.id = pc.course_id
GROUP BY PersonID;