【问题标题】:SQL - table alias scopeSQL - 表别名范围
【发布时间】:2008-10-09 19:30:41
【问题描述】:

我刚刚(昨天)学会了使用“exists”而不是“in”。

 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 有效?

非常感谢

【问题讨论】:

  • 第二个查询不解析。文本提到“第二个存在”所以你的意思是AND exists ( 用于AND?

标签: sql scope table-alias


【解决方案1】:

它特定于每个 DBMS,并取决于查询优化器。一些优化器检测 IN 子句并翻译它。

在我测试的所有 DBMS 中,别名仅在 () 内有效

顺便说一句,您可以将查询重写为:

select t.* 
from table t 
join othertable o on t.nameid = o.nameid 
    and o.otherdesc in ('SomeDesc','SomeOtherDesc');

并且,回答您的问题:

  1. 是的
  2. 是的
  3. 是的

【讨论】:

    【解决方案2】:

    您正在涉足复杂领域,称为“相关子查询”。由于我们没有关于您的表格和关键结构的详细信息,因此某些答案只能是“可能”。

    在您的初始 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 中具有该 NameID 值的每一行的两个 OtherDesc 值。

    【讨论】:

      【解决方案3】:
      1. Oracle 特定:当您使用 IN 子句编写查询时,您是在告诉基于规则的优化器您希望内部查询驱动外部查询。当您在 where 子句中编写 EXISTS 时,您是在告诉优化器您希望首先运行外部查询,并使用每个值从内部查询中获取一个值。见"Difference between IN and EXISTS in subqueries"
      2. 可能。
      3. 在子查询中声明的别名存在于子查询中。顺便说一句,我认为您的带有 2 个 AND 子查询的示例不是有效的 SQL。您是说 UNION 而不是 AND?

      【讨论】:

        【解决方案4】:

        我个人会为此使用联接,而不是子查询。

        SELECT t.*
        FROM yourTable t
            INNER JOIN otherTable ot
                ON (t.nameid = ot.nameid AND ot.otherdesc = 'SomeDesc')
        

        【讨论】:

          【解决方案5】:

          很难概括 EXISTS 总是比 IN 好。从逻辑上讲,如果是这种情况,那么 SQL 社区将用 EXISTS 替换 IN... 另外,请注意IN和EXISTS是不一样的,当你使用两者时,结果可能会不同...

          使用 IN,通常它会在不删除 NULL 的情况下对内表进行一次全表扫描(因此,如果您的内表中有 NULL,IN 默认情况下不会删除 NULL)......而 EXISTS 会删除 NULL,并且在相关子查询,它对外部查询的每一行运行内部查询。

          假设没有 NULLS 并且它是一个简单的查询(没有相关性),如果您找到的行不是最后一行,则 EXIST 可能会执行得更好。如果它恰好是最后一行,EXISTS 可能需要像 IN 一样扫描到最后......所以类似的性能......

          但 IN 和 EXISTS 不可互换...

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-07-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多