SQL 以多对多关系查找不属于特定集合的所有元素
SQL Finding all elements which does not belong to a particular set, in many to many relation
我对这个任务有疑问:
Given are the relations
Students: ST (S#, SNAME)
Lecture: L (L#, LNAME, ECTS)
Who attends what: LS (L#, S#)
Find students (S# and SNAME) who do not attend any lecture having more
than 4 ECTS
我知道我可以通过检查给定学生的 ECTS 最大值是否大于 4 来做到这一点,但作为学习的一部分,我想以不同的方式进行。即我想使用子查询来做到这一点:
SELECT S.[S#], SNAME
FROM ST
INNER JOIN LS ON LS.[S#] = S.[S#]
WHERE LS.[L#] /* and here is a problem, I want a statement like "none of LS.[L#] exists in" */ (SELECT [L#] FROM L WHERE ECTS > 4)
我的想法是 (SELECT [L#] FROM L WHERE ECTS > 4)
将 return 所有 ECTS 大于 4 的讲座,然后我只需要检查此集合中是否存在其中一个通过 LS table 分配给 Student,然后跳过它。
我知道存在 ALL 和 ANY 等运算符,但它似乎在任何配置下都不起作用。
我试过例如 WHERE NOT LS.[L#] = ANY (SELECT [L#] FROM L WHERE ECTS > 4)
,但由于它根据 LS.[L#]
单独运行,它只是 return 让我的学生至少有一个 ECTS <= 4
的讲座。
我发现 WHERE LS.[L#] = ANY (SELECT [L#] FROM L WHERE ECTS > 4)
完全否定了我想要的集合 - 天真地我认为不会反转这个集合 - 但显然不会 - 在这种情况下我想要的是 ALL STUDENTS - WHERE LS.[L#] = ANY (SELECT [L#] FROM L WHERE ECTS > 4)
.
这个问题有这种方式的巧妙解决方案吗?
您可以按如下方式使用not exists
:
SELECT S.[S#], SNAME
FROM ST
INNER JOIN LS ON LS.[S#] = S.[S#]
WHERE not exists
(select 1 from L
Where L.[L#] = LS.[L#]
AND L.ECTS > 4)
使用我们将命名为“Temp”的子查询,其中包含 参加 超过 4 ECTS 的讲座的学生列表,我们可以 select 从使用 LEFT JOIN 不在该列表中的学生:
SELECT
ST.[S#],
ST.SNAME
FROM ST
LEFT JOIN
(SELECT LS.[S#]
FROM SL
JOIN L
ON SL.[L#] = L.[L#]
WHERE L.ECTS > 4
) AS Temp
ON ST.[S#] = Temp.[S#]
WHERE Temp.[S#] IS NULL
可以使用NOT EXISTS
,但正确的逻辑是:
SELECT S.[S#], s.SNAME
FROM S
WHERE NOT EXISTS (SELECT 1
FROM LS JOIN
L
ON L.[L#] = LS.[L#]
WHERE LS.[S#] = S.[S#] AND L.ECTS > 4
) ;
也就是你要加入子查询
我对这个任务有疑问:
Given are the relations
Students: ST (S#, SNAME)
Lecture: L (L#, LNAME, ECTS)
Who attends what: LS (L#, S#)
Find students (S# and SNAME) who do not attend any lecture having more than 4 ECTS
我知道我可以通过检查给定学生的 ECTS 最大值是否大于 4 来做到这一点,但作为学习的一部分,我想以不同的方式进行。即我想使用子查询来做到这一点:
SELECT S.[S#], SNAME
FROM ST
INNER JOIN LS ON LS.[S#] = S.[S#]
WHERE LS.[L#] /* and here is a problem, I want a statement like "none of LS.[L#] exists in" */ (SELECT [L#] FROM L WHERE ECTS > 4)
我的想法是 (SELECT [L#] FROM L WHERE ECTS > 4)
将 return 所有 ECTS 大于 4 的讲座,然后我只需要检查此集合中是否存在其中一个通过 LS table 分配给 Student,然后跳过它。
我知道存在 ALL 和 ANY 等运算符,但它似乎在任何配置下都不起作用。
我试过例如 WHERE NOT LS.[L#] = ANY (SELECT [L#] FROM L WHERE ECTS > 4)
,但由于它根据 LS.[L#]
单独运行,它只是 return 让我的学生至少有一个 ECTS <= 4
的讲座。
我发现 WHERE LS.[L#] = ANY (SELECT [L#] FROM L WHERE ECTS > 4)
完全否定了我想要的集合 - 天真地我认为不会反转这个集合 - 但显然不会 - 在这种情况下我想要的是 ALL STUDENTS - WHERE LS.[L#] = ANY (SELECT [L#] FROM L WHERE ECTS > 4)
.
这个问题有这种方式的巧妙解决方案吗?
您可以按如下方式使用not exists
:
SELECT S.[S#], SNAME
FROM ST
INNER JOIN LS ON LS.[S#] = S.[S#]
WHERE not exists
(select 1 from L
Where L.[L#] = LS.[L#]
AND L.ECTS > 4)
使用我们将命名为“Temp”的子查询,其中包含 参加 超过 4 ECTS 的讲座的学生列表,我们可以 select 从使用 LEFT JOIN 不在该列表中的学生:
SELECT
ST.[S#],
ST.SNAME
FROM ST
LEFT JOIN
(SELECT LS.[S#]
FROM SL
JOIN L
ON SL.[L#] = L.[L#]
WHERE L.ECTS > 4
) AS Temp
ON ST.[S#] = Temp.[S#]
WHERE Temp.[S#] IS NULL
可以使用NOT EXISTS
,但正确的逻辑是:
SELECT S.[S#], s.SNAME
FROM S
WHERE NOT EXISTS (SELECT 1
FROM LS JOIN
L
ON L.[L#] = LS.[L#]
WHERE LS.[S#] = S.[S#] AND L.ECTS > 4
) ;
也就是你要加入子查询