2

O.我已经尝试解决这个问题两天了,没有成功,我的所有工作都因此而停止。

切入正题:

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

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

但。这将返回任何这些课程的学生。

如果我将 WHERE 子句更改为:

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

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

我该怎么做呢?我在这里缺少的 SQL 理论是什么?我意识到 SQL 按行工作,所以我需要按行过滤。但我确信这是一个常见的查询,我只是找不到理论的名称或我在这里缺少的东西来解决它。

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

非常感谢您的帮助。

4

4 回答 4

4

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

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
于 2012-04-24T19:27:00.797 回答
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);
于 2012-04-24T19:21:57.087 回答
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 逻辑。

希望能帮助到你!

于 2012-04-24T19:24:33.670 回答
1

另一种方法是使用集合运算符查询。我将使用哪个取决于学生是否可以注册同一课程的多个部分,以及我是否希望出现重复项。通过多个连接,理论上您可以返回一个学生的多个副本。如果我希望每个学生出现一次,那么我会使用 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 行。

于 2012-04-24T21:30:33.563 回答