SQL:保证与多对多查询匹配的N行完全匹配?

时间:2012-04-24 19:18:19

标签: sql many-to-many

0。我一直试图让这个解决了两天,没有成功,因为它我的所有工作都停止了。

关键点:

我在这三个表之间有多对多的关系:

Students
Students_Courses
Courses

我需要确切地知道哪些学生注册了物理和微积分和CS101

他们可以报名参加其他课程,但我需要知道这三门课程中有哪些。

SELECT * FROM Students A 
INNER JOIN Students_Courses B on A.id = B.student
INNER JOIN Courses C on B.course = C.id
WHERE C.name = Physics OR C.name = calculus OR C.name = cs101

BUT。这将使学生返回任何一门课程。

如果我将WHERE子句更改为:

WHERE C.name = Physics AND C.name = calculus AND C.name = cs101

它不会返回任何内容,因为没有这样的行匹配所有三个。

我该怎么做?我在这里缺少什么SQL理论?我意识到SQL每行都有效,所以我需要每行过滤。但我确信这是一个常见的查询我只是找不到理论的名称或我在这里为了解决它而失踪的东西。

我确实通过选择所有这些课程然后过滤哪些学生匹配这三个课程来解决它,但这是在应用程序中,我希望这可以是单个SQL查询。

非常感谢您的帮助。

4 个答案:

答案 0 :(得分:4)

SELECT student
FROM Students
WHERE student IN (SELECT student FROM Students_Courses B INNER JOIN Courses C on B.course = C.id WHERE C.name = Physics) AND
student IN (SELECT student FROM Students_Courses B INNER JOIN Courses C on B.course = C.id WHERE C.name = calculus) AND
student IN (SELECT student FROM Students_Courses B INNER JOIN Courses C on B.course = C.id WHERE C.name = cs101);

答案 1 :(得分:4)

mitch的解决方案会更好用,但这是另一种乐趣。

SELECT A.id FROM Students A 
INNER JOIN Students_Courses B on A.id = B.student
INNER JOIN Courses C on B.course = C.id
WHERE C.name = Physics OR C.name = calculus OR C.name = cs101
GROUP BY A.id
HAVING count(DISTINCT C.id) = 3

答案 2 :(得分:2)

为了在连接中执行AND逻辑,我通常只是多次加入有问题的表。

SELECT * FROM Students A 
INNER JOIN Students_Courses B on A.id = B.student
INNER JOIN Courses C1 on B.course = C1.id
INNER JOIN Courses C2 on B.course = C2.id
INNER JOIN Courses C3 on B.course = C3.id
WHERE C1.name = Physics AND C2.name = calculus AND C3.name = cs101

我不能肯定这是最有效的方式,但是当你从以行为中心的角度思考时,这是有道理的。如果每个“INNER JOIN”子句能够从关系的“叶子”表中获取一行,那么将需要三个“INNER JOIN”子句来获得三行,以便您可以将AND逻辑应用于它们。

希望它有所帮助!

答案 3 :(得分:1)

另一种方法是使用set运算符查询。我使用哪个取决于学生是否可以注册同一课程的多个部分,以及我是否希望重复出现。通过多个连接,理论上可以返回学生的许多副本。如果我希望每个学生出现一次,那么我将使用set运算符:

SELECT A.STUDENTID 
FROM Students A  
INNER JOIN Students_Courses B 
    on A.id = B.student 
INNER JOIN Courses C1 
    on B.course = C1.id 
WHERE C1.name = 'Physics'
INTERSECT
SELECT A.STUDENTID 
FROM Students A  
INNER JOIN Students_Courses B 
    on A.id = B.student 
INNER JOIN Courses C2 
    on B.course = C2.id 
WHERE C2.name = 'calculus'
INTERSECT
SELECT A.STUDENTID 
FROM Students A  
INNER JOIN Students_Courses B 
    on A.id = B.student 
INNER JOIN Courses C3 
    on B.course = C3.id 
WHERE C3.name = 'cs101' 

修改 另一种方法是使用聚合:

SELECT A.STUDENTID 
    , COUNT(distinct c3.name)
FROM Students A  
INNER JOIN Students_Courses B 
    on A.id = B.student 
INNER JOIN Courses C3 
    on B.course = C3.id 
WHERE C3.name IN 
    (   'cs101' 
        , 'calculus'
        , 'Pysics'
    )
GROUP BY a.studentid
HAVING COUNT(DISTINCT c3.name) = 3

对于所有三门课程中至少有一部分的学生,这两项都只返回一次学生数据。如果学生不能在每个名称的多个课程中,那么它将返回与上面的多个联接版本相同的名称。如果他能,那么2个物理课程,2个微积分课程和3个cs101课程的学生将使用多个连接返回12行。