Sql server TSQL子查询行为

Sql server TSQL子查询行为,sql-server,tsql,sql-server-2016,Sql Server,Tsql,Sql Server 2016,我发现我的子查询并没有在应该的时候引发错误。问题并没有指出这是一个潜在的问题,所以我相信我肯定遗漏了查询引擎如何工作的一些更基本的东西。复制: -- 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

我发现我的子查询并没有在应该的时候引发错误。问题并没有指出这是一个潜在的问题,所以我相信我肯定遗漏了查询引擎如何工作的一些更基本的东西。复制:

-- 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'.
但是完整查询会返回一个虚假的结果,而不会引发错误


无论这里发生了什么,它是由微软或SQL-92标准正式记录的吗?谢谢

它与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);
我知道这很烦人,而且没有文档记录,看起来像个bug,但事实并非如此。如果列名与范围中所有有效列中的一列匹配,则它将使用该列。这就是这里发生的事情。有一些编码实践可以阻止这些陷阱,即对所有东西都使用别名

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


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

< P>子查询“列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);

为避免意外结果,请始终为表别名。

谢谢,可以。很明显,这就是查询引擎变得混乱的地方。我应该澄清我的问题——别名要求是否有文档记录?“查询引擎变得混乱”-不,没有。这就是它的工作原理。“这就是它的工作原理”-正式记录在哪里?你可以深入研究相关子查询如何工作的定义,你可能会在那里找到一些东西,但我真的不会打扰你。所有这些都是完全合乎逻辑且可重复的。谢谢-别名建议/要求是否有文档记录?对不起,我的意思是它是否有正式文档记录?或者别名是一种解决方法吗?8年前,有人提出了一个相同的问题,但答案似乎仍然是一样的:子查询行为是未记录的,别名是最好的解决方法。它没有任何未记录的内容。每个RDBMS都将以这种方式运行。它是标准的SQL。“它没有任何未记录的内容”-您可以链接到解决我问题的任何文档吗?子查询创建用于解析列名的嵌套范围。如果在最里面的查询中找不到列名,则按顺序检查外部查询以解析名称。只要找到一个不含糊的匹配,也就是说,它不会归结为两个(或多个)具有相同列名的联接表,就不会有歧义或错误。最佳实践是在所有列引用上始终使用有意义的表别名。(想象一下,如果有一天有人更改/添加/删除了一个列名,导致现有的查询将引用转移到另一个表中。一个错误会更好。)vintage standard中的第5.4.12节怎么样?(提示:搜索“嵌套”。)