我刚学会(昨天)使用“存在”而不是“在”。
BAD
select * from table where nameid in (
select nameid from othertable where otherdesc = 'SomeDesc' )
GOOD
select * from table t where exists (
select nameid from othertable o where t.nameid = o.nameid and otherdesc = 'SomeDesc' )
我对此有一些疑问:
1)我理解的解释是:“之所以更好是因为只返回匹配的值而不是构建大量可能的结果列表”。这是否意味着虽然第一个子查询可能返回900个结果,但第二个子查询只返回1(是或否)?
2)过去我曾抱怨过RDBMS:“只检索前1000行”,第二种方法可以解决这个问题吗?
3)第二个子查询中别名的范围是什么?...别名是否仅存在于括号中?
例如
select * from table t where exists (
select nameid from othertable o where t.nameid = o.nameid and otherdesc = 'SomeDesc' )
AND
select nameid from othertable o where t.nameid = o.nameid and otherdesc = 'SomeOtherDesc' )
也就是说,如果我使用相同的别名(o表用于其他表)在第二个“存在”中它是否会出现第一个存在的问题?还是他们完全独立?
这是Oracle唯一相关的,还是对大多数RDBMS有效?
非常感谢
答案 0 :(得分:4)
它特定于每个DBMS并依赖于查询优化器。一些优化器检测IN子句并将其翻译。
在我测试的所有DBMS中,别名仅在()
中有效顺便说一句,您可以将查询重写为:
select t.*
from table t
join othertable o on t.nameid = o.nameid
and o.otherdesc in ('SomeDesc','SomeOtherDesc');
并回答你的问题:
答案 1 :(得分:3)
您正在进入复杂的领域,称为“相关子查询”。由于我们没有关于您的表格和关键结构的详细信息,因此一些答案只能是“可能”。
在您的初始IN查询中,无论OtherTable是否包含列NameID(并且确实,OtherDesc是否作为Table或OtherTable中的列存在),该表示法都是有效的 - 这在您的任何示例中都不清楚,但可能是是OtherTable的一列。此行为是将相关子查询转换为相关子查询的原因。当人们第一次遇到焦虑时,这也是一种常见的焦虑源 - 总是偶然发生。由于SQL标准要求将子查询中的名称解释为引用外部查询中的列,如果子查询中提到的表中没有相关名称的列,但是有一个列外部(主)查询中提到的表中的相关名称,没有想要声明符合(这一点)SQL标准的产品将做任何不同的事情。
您的Q1的答案是“它取决于”,但是给出了合理的假设(NameID在两个表中都作为列存在; OtherDesc仅存在于OtherTable中),结果应该与返回的数据集相同,但是可能在性能方面不相同。
你的Q2的答案是,在过去,你使用的是劣质的,如果没有缺陷的DBMS。如果它支持EXISTS,那么DBMS可能仍会抱怨结果的基数。
应用于第一个EXISTS查询的Q3的答案是“t在整个语句中可用作别名,但o仅作为括号内的别名”。应用于你的第二个示例框 - 使用AND连接两个子选择(当我查看它时,第二个缺少开括号),然后“t在整个语句中作为别名可用并引用相同的表,但有两个不同的别名都标记为'o',每个子查询一个“。请注意,如果OtherDesc对于OtherTable中的给定NameID值是唯一的,则查询可能不返回任何数据;否则,它需要在OtherTable中有两行具有相同的NameID,并且Table中每行的两个OtherDesc值都需要具有该NameID值。
答案 2 :(得分:2)
答案 3 :(得分:1)
我个人会使用连接,而不是子查询。
SELECT t.*
FROM yourTable t
INNER JOIN otherTable ot
ON (t.nameid = ot.nameid AND ot.otherdesc = 'SomeDesc')
答案 4 :(得分:1)
很难概括EXISTS总是优于IN。从逻辑上讲,如果是这种情况,则SQL社区将用EXISTS替换IN ... 此外,请注意IN和EXISTS不相同,当您使用这两个时结果可能会有所不同......
使用IN,通常是内表的全表扫描一次而不删除NULL(所以如果你的内表中有NULL,默认情况下IN不会删除NULLS)...当EXISTS删除NULL时,如果是相关子查询,它为外部查询中的每一行运行内部查询。
假设没有NULLS及其简单查询(没有相关性),如果您找到的行不是最后一行,则EXIST可能会表现得更好。如果恰好是最后一行,EXISTS可能需要像IN一样扫描到最后..所以类似的性能......
但IN和EXISTS不可互换......