SQL:连接多个表

Posted

技术标签:

【中文标题】SQL:连接多个表【英文标题】:SQL : join more than one table 【发布时间】:2020-10-11 06:11:51 【问题描述】:

编写一个 sql 查询来选择参加过“JOHN”教授的所有讲座但没有参加过“JOSEPH”教授的任何讲座的学生的姓名。

我已经写了这个查询,但它给了我正在听约瑟夫讲课的学生的名字。

select distinct s.studentname 
from Student s,Attendance a,Lecture l 
where s.StudentId=a.studid 
  and l.lecId = a.lectureid 
  and l.professor='JOHN' 
  and l.professor != 'JOSEPH';

我在上述查询中犯了一些错误,但无法识别。

这是表结构

学生桌

# StudentId, StudentName, Sex
'1', 'AMY', 'M'
'2', 'JACK', 'M'
'3', 'TONY', 'M'
'4', 'TARA', 'M'
'5', 'SARAH', 'F'
'6', 'TOM', 'F'

讲台

# LecId, Subject, Professor
1, MATH, JOHN
2, MATH, JOSEPH
3, PHY, MARK
4, PHY, MAX
5, PHY, JOHN
6, CHEM, JOHN
7, CHEM, JOSEPH
8, HISTORY, JOSEPH

考勤表

# StudId, LectureId
'1', '1'
'1', '2'
'3', '1'
'2', '5'
'2', '6'
'3', '4'
'1', '6'
'4', '5'
'5', '1'
'5', '2'
'1', '3'
'1', '4'
'1', '5'
'1', '6'

【问题讨论】:

请在代码问题中给出minimal reproducible example--cut & paste & runnable code,包括最小的代表性示例输入作为代码;期望和实际输出(包括逐字错误消息);标签和版本;明确的规范和解释。给出尽可能少的代码,即您显示的代码可以通过您显示的代码扩展为不正常的代码。 (调试基础。)对于包含 DBMS 和 DDL(包括约束和索引)和输入为格式化为表的代码的 SQL。 How to Ask 暂停总体目标的工作,将代码砍到第一个表达式,没有给出你期望的内容,说出你期望的内容和原因。 您使用的连接语法在 1992 年的标准 SQL 中变得多余。那是在 mysql 发明之前!如果您正在上课或使用一本书或教程教您使用这种古老的语法,您应该退出它。请改用正确的显式连接(INNER JOINLEFT OUTER JOIN 等)。 【参考方案1】:

您需要查看属于给定学生的所有行,因此简单的where 子句无法满足您的要求。相反,您可以使用带有 having 子句的聚合和文件管理器:

select s.studentname 
from student s
inner join attendance a on s.studentId = a.studid
inner join lecture l on l.lecId = a.lectureid 
group by s.studentId, s.studentname 
having max(l.professor= 'JOHN') = 1 and max(l.professor = 'JOSEPH') = 0

如果您希望教师添加所有约翰的讲座,而不是约瑟夫的讲座,那么:

select s.studentname 
from student s
inner join attendance a on s.studentId = a.studid
inner join lecture l on l.lecId = a.lectureid 
group by s.studentId, s.studentname 
having 
    sum(l.professor= 'JOHN') = (select count(*) from lecture where professor = 'JOHN')
    and max(l.professor = 'JOSEPH') = 0

【讨论】:

嘿,抱歉,对问题做了一点改动,这将产生很大的影响.. 非常抱歉,您现在能帮帮我吗:)【参考方案2】:

如果你的 MySQL 版本支持 GROUP_CONCAT,你可以试试下面的脚本-

Demo Here

SELECT S.StudentId,S.StudentName, GROUP_CONCAT(DISTINCT L.Professor)
FROM Attendance A
INNER JOIN Lecture L ON A.LectureId = L.LecId
INNER JOIN Student S ON A.StudId = S.StudentId
GROUP BY S.StudentId,S.StudentName
HAVING  GROUP_CONCAT(DISTINCT L.Professor) = 'JOHN'

以上查询将返回仅从“JOHN”学习课程的学生列表。没有其他人。

但如果您的要求更改为在列表中添加更多教授,您可以在 HAVING 子句检查中相应地添加教授名称。但是您需要在这种情况下应用适当的排序。

【讨论】:

接近了,但为什么它没有给出 JACK 的名字,学生:2,他也只参加了 JOHN 是的,应该有 2 个,检查中 更改了一点@sparsh610 请检查【参考方案3】:

试试:

select * from Student st
where exists(select * from Lecture l
             join Attendance a
             on l.LecId = a.LectureId
             where l.Professor = 'John'
             and a.StudId = st.StudentId)
and exists(select * from Lecture l
               join Attendance a
               on l.LecId = a.LectureId
               where l.Professor = 'Joseph'
               and a.StudId = st.StudentId)

【讨论】:

@sparsh610 能否请您添加 DDL 以便我进行测试?此外,托尼也满足要求。你目前的结果是什么? 如何在 mysql 中获取? 只需将数据放入sqlfiddle.com并分享链接 嘿,抱歉,对问题做了一点改动,这将产生很大的影响.. 非常抱歉,您现在能帮帮我吗:) @sparsh610 立即尝试。【参考方案4】:
select s.StudentName 
from Student s
inner join Attendance a on s.StudentId = a.StudId
inner join Lecture l on l.LecId = a.LectureId 
group by s.StudentId, s.StudentName 
having 
    sum(l.Professor= 'JOHN') = (select count(*) from lecture where Professor = 'JOHN')
    and max(l.Professor = 'JOSEPH') = 0
order by s.StudentName

#asked in interview (MakeMyTrip)

【讨论】:

感谢您添加到答案列表中。虽然有些人可能能够立即了解您分享的内容,但其他人可能不会。除了代码之外,至少添加一点上下文会更有帮助。【参考方案5】:

我重新表述了你所做的加入...但它似乎有效。

此查询是否返回您要查找的数据集?

SELECT s.studentname, l.Subject, l.Professor
FROM Student s JOIN Attendance a
ON s.StudentId = a.StudId
JOIN Lecture l 
ON l.lecId = a.lectureid
WHERE l.professor='JOHN' 
  AND l.professor != 'JOSEPH';

【讨论】:

【参考方案6】:

MSSQL:

WITH cte AS
(
    SELECT StudentName, ROW_NUMBER() 
    OVER(
        PARTITION BY studid
        ORDER BY studid
    ) cou 
    FROM attendance a,lecture l,student s 
    WHERE a.LectureId = l.LecId
    AND a.StudId = s.StudentId
    AND l.Professor = 'john'
)
SELECT StudentName
FROM cte
WHERE cou = 3

Except

SELECT StudentName
FROM attendance a, lecture l, student s 
WHERE a.LectureId = l.LecId
AND a.StudId = s.StudentId
AND l.Professor = 'joseph'

【讨论】:

我在 studid 上使用 partitionby 并获取参加了所有 john 三个班级的学生(where 子句的条件)。我使用 cou=3 来抓取参加了 john 的所有 3 个班级的学生。在下一步中,我将在学生使用 cte 表参加 joseph 课程的桌子上使用 except。在这里我得到了想要的输出,表 a 排除了表 b 中存在的标准名称。

以上是关于SQL:连接多个表的主要内容,如果未能解决你的问题,请参考以下文章

SQL:连接多个表

在连接表语句中访问 SQL 多个 HAVING

(My)SQL:连接多个表

连接多个表后如何从sql查询结果中删除重复记录

SQL:具有相似表的多个左连接

SQL 左连接与 FROM 行上的多个表?