这很简单,当你掌握了它的窍门时:
SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
WHERE s.S_Sex = 'F'
AND S.S_Id NOT IN(SELECT e.S_Id -- take this line
FROM ENROLLMENT e
WHERE e.Mark < 70);
该行基本上与来自子查询S.S_Id的所有值进行比较。e.S_Id
现在将其更改为NOT EXISTS并在子查询中放置一个相等检查S.S_Id = e.S_Id:
SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
WHERE s.S_Sex = 'F'
AND NOT EXISTS (SELECT e.S_Id
FROM ENROLLMENT e
WHERE (e.Mark < 70) -- if this is complex, you'll need parentheses
AND S.S_Id = e.S_Id);
微小的可能变化是意识到(SELECT e.S_Id ...并不真正需要e.S_Id. 子查询EXISTS只NOT EXISTS检查是否有行返回,列值无关紧要。您可以在SELECT *那里放置一个常量(SELECT 1很常见)SELECT NULL甚至SELECT 1/0(是的,这会起作用!):
SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
WHERE s.S_Sex = 'F'
AND NOT EXISTS (SELECT 1
FROM ENROLLMENT e
WHERE e.Mark < 70
AND S.S_Id = e.S_Id);
另一个主要考虑因素是,当您以这种方式进行转换时,只有当两列都不可为空时,查询的(看似等效的)NOT EXISTS和NOT IN写入才真正等效。S_Id如果该e.S_Id列可以为空,则NOT IN可能导致整个查询根本不返回任何行(因为当其中一个x NOT IN (a, b, c, ...)为x<>a AND x<>b AND ...时,该条件不能为真a,b,c...。NULL)
出于类似的原因,如果 可以为空,您将得到不同的结果s.S_Id(在这种情况下不太可能,因为它可能是主键,但在其他情况下很重要。)
因此,使用 几乎总是更好NOT EXISTS,因为即使任一列可以为空(S.S_Id = e.S_Id检查将丢弃之前为 null 的行),它的行为也会有所不同,并且通常这种行为是想要的行为。问题中有很多细节:NOT IN vs NOT EXISTS,@Martin Smith 的回答。您还将找到将其转换NOT IN为NOT EXISTS并保持与 null 相关(不愉快)行为的方法。