【问题标题】:TSQL Subquery BehaviorTSQL 子查询行为
【发布时间】:2018-09-08 04:10:07
【问题描述】:

我发现我的子查询并没有在应该引发错误的时候引发错误。 docs 并不表示这是一个潜在的问题,所以我相信我一定错过了查询引擎如何工作的更基本的东西。重现:

-- create and populate two tables with unique column names
create table tbl1 (col1 int);
insert tbl1 values (1);
create table tbl2 (col2 int);
insert tbl2 values (2);

-- execute query and subquery 
select col1 from tbl1 
    where col1 in (select col1 from tbl2);

子查询单独返回预期的错误:

Invalid column name 'col1'.

但是完整的查询返回了一个虚假的结果而没有引发错误。

这里发生了什么,它是由 Microsoft 还是 SQL-92 标准正式记录的?谢谢!

【问题讨论】:

  • 8 多年前,here 提出了一个相同的问题,但答案似乎仍然相同:子查询行为未记录,别名是最好的解决方法
  • 没有任何未记录的内容。每个 RDBMS 都会以这种方式运行。它是标准 SQL。
  • “没有任何未记录的内容” - 您可以链接到任何解决我问题的文档吗?
  • 子查询为解析列名创建了一个嵌套范围。如果在最里面的查询中找不到列名,则检查外部查询,以便解析名称。只要找到非歧义匹配,即它不会归结为两个(或多个)具有相同列名的连接表,就没有歧义或错误。最佳做法是始终对所有列引用使用有意义的 表别名。 (想象一下,如果有一天有人更改/添加/删除了列名,导致现有查询将引用转移到不同的表。出错更好。)
  • this 复古标准中的第 5.4.12 节怎么样? (提示:搜索“嵌套”。)

标签: sql-server tsql sql-server-2016


【解决方案1】:

对列'col1'的子查询引用实际上是指外部表:

select col1 from tbl1 
    where col1 in (select col1 from tbl2);
                          ^^^  this is 'col1' in table 'tbl1'

这符合预期:

select t1.col1 from tbl1 t1
    where t1.col1 in (select t2.col1 from tbl2 t2);

为避免意外结果,请始终为您的表设置别名。

【讨论】:

  • 谢谢 - 别名建议/要求是否记录在案?
  • 对不起,我的意思是它有官方记录吗?或者别名是否是一种解决方法?
【解决方案2】:

它与 tbl1 相关。 总是给你的表起别名

这个按预期运行

create table tbl1 (col1 int);
insert tbl1 values (1);
create table tbl2 (col2 int);
insert tbl2 values (2);

-- execute query and subquery 
select col1 from tbl1 
    where col1 in (select Z.col1 from tbl2 Z);

我知道这很烦人并且没有记录,看起来像是一个错误,但事实并非如此。如果您的列名与范围内所有有效列中的 一个 列匹配,则它使用该列。这就是这里发生的事情。有一些编码实践可以阻止这些陷阱,即别名化所有内容。

我不会将别名称为解决方法。这里没有解决方法 - 这完全合乎逻辑。

您可以深入研究相关子查询如何工作的定义,您可能会找到答案,但我认为这是一个经验教训。

【讨论】:

  • 谢谢,可以。很明显,这就是查询引擎感到困惑的地方。我应该澄清我的问题——别名要求是否记录在案?
  • " 查询引擎变得混乱" - 不,不是。这就是它的工作原理。
  • “这就是它的工作原理” - 官方记录在哪里?
  • 您可以深入了解相关子查询如何工作的定义,您可能会在那里找到一些东西,但我真的不会打扰。这一切都是完全合乎逻辑和可重复的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多