Sql 将不在转换为不存在
有一个噩梦般的时间来理解NOT EXISTS的用法,主要是如何在下面的解决方案中转换我的NOT,以便我能够真正理解我是如何实现结果的。 有几篇关于askTom、oracle论坛和stackoverflow的文章,但找不到任何有助于理解此问题的文章。如果我在noobish搜索中错过了它,我深表歉意Sql 将不在转换为不存在,sql,oracle,Sql,Oracle,有一个噩梦般的时间来理解NOT EXISTS的用法,主要是如何在下面的解决方案中转换我的NOT,以便我能够真正理解我是如何实现结果的。 有几篇关于askTom、oracle论坛和stackoverflow的文章,但找不到任何有助于理解此问题的文章。如果我在noobish搜索中错过了它,我深表歉意 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
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
FROM ENROLLMENT e
WHERE e.Mark < 70);
在内容上提供一点帮助,试图找到那些在所注册的任何班级中从未获得低于70分的女生。当你掌握窍门时,这相当简单:
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);
可能的微小变化是认识到选择e.S_Id。。。实际上不需要e.S_Id。具有EXISTS和not EXISTS的子查询只需检查是否返回了行,列值无关紧要。您可以将SELECT*或常量放入其中,选择1是公共的,或者选择NULL,甚至选择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);
另一个主要考虑因素是,当您以这种方式进行转换时,只有当两个S_Id列都不可为空时,表面上等价的不存在,并且在查询的编写中不存在的才是真正等价的。如果e.S_Id列可为空,则NOT IN可能导致整个查询不返回任何行,因为x不在a、b、c、。。。相当于xa和xb以及。。。当a,b,c中的一个。。。是空的
出于类似的原因,如果s.s_Id可为空,则会得到不同的结果。在本例中,这不太可能,因为它可能是主键,但在其他情况下,它很重要
因此,使用NOT EXISTS几乎总是更好的,因为即使任一列都可以为null,它的行为也会有所不同。s.s_Id=e.s_Id检查将在前面丢弃具有null的行,通常这种行为是需要的。问题中有许多细节:,在@Martin Smith的回答中。您还可以找到将NOT IN转换为NOT EXISTS的方法,并保持与null相关的不愉快行为。这不完全是您所要求的,但这里有一种方法可以在不存在NOT EXISTS的情况下实现这一点-创建“70岁以下的成就者”作为派生表,左外连接它并检查是否有空值,如下图所示
SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
LEFT JOIN
(
SELECT S_Id
FROM ENROLLMENT
WHERE Mark < 70
) e ON e.S_Id = s.S_Id
WHERE e.S_Id IS NULL
AND s.S_Sex = 'F';
也可能有助于您对SQL的一般理解。这两种方法都有利弊
精彩的你是对的,现在看解决方案时,这是非常有意义的。not exists子句乍一看有点痛苦,但一旦您了解如何消除不必要的行,它就会像一个符咒一样工作。谢谢+1您可能会注意到,在许多情况下,乐观主义者无论如何都会将它们转换为相同的执行计划-我认为只有在e.s_id不为null的情况下,这是确保该id不为null的另一个很好的理由。我没有看到您的查询中不存在的部分。OP想了解不存在的问题。它只是帮助OP扩大对SQL理解的另一种解决方案。
SELECT s.S_Fname, s.S_Lname
FROM STUDENT s
LEFT JOIN
(
SELECT S_Id
FROM ENROLLMENT
WHERE Mark < 70
) e ON e.S_Id = s.S_Id
WHERE e.S_Id IS NULL
AND s.S_Sex = 'F';