使用SQL Server Management Studio,我得到了一些不受欢迎的结果(看起来像是一个bug ...?)
如果我使用(而不是字段用于other_table):
SELECT * FROM main_table WHERE field IN (SELECT FIELD FROM other_table)
我从main_table获得了所有结果。
使用正确的案例:
SELECT * FROM main_table WHERE field IN (SELECT field FROM other_table)
我得到了预期结果,其中字段出现在其他字段中。
自己运行子查询:
SELECT FIELD FROM other_table
我收到无效的列名错误。
我肯定会在第一种情况下得到这个错误吗?
这与整理相关吗? DB是二进制排序规则。 但是,服务器不区分大小写。 在我看来,像服务器组件说“这段代码没问题”并且不允许DB说这个字段是错误的名字..?
我对解决方案有哪些选择?
答案 0 :(得分:5)
让我们用不依赖于区分大小写的东西来说明正在发生的事情:
USE tempdb;
GO
CREATE TABLE dbo.main_table(column1 INT);
CREATE TABLE dbo.other_table(column2 INT);
INSERT dbo.main_table SELECT 1 UNION ALL SELECT 2;
INSERT dbo.other_table SELECT 1 UNION ALL SELECT 3;
SELECT column1 FROM dbo.main_table
WHERE column1 IN (SELECT column1 FROM dbo.other_table);
结果:
column1
-------
1
2
为什么不引发错误? SQL Server正在查看您的查询并发现其中的column1不可能位于other_table中,因此它正在外推并“使用”外部引用表中存在的column1(就像您可以引用仅存在于其中的列一样)没有表引用的外表)。想想这种变化:
SELECT [column1] FROM dbo.main_table
WHERE EXISTS (SELECT [column1] FROM dbo.other_table WHERE [column2] = [column1]);
结果:
column1
-------
1
同样,SQL Server知道where子句中的column1在本地引用的表中也不存在,但它尝试在外部作用域中找到它。因此,在虚构的世界中,您可能会认为查询实际上是在说:
SELECT m.[column1] FROM dbo.main_table AS m
WHERE EXISTS (SELECT m.[column1] FROM dbo.other_table AS o WHERE o.[column2] = m.[column1]);
(这不是我打字的方式,但是如果我这样输入它,它仍然有效。)
在某些情况下,它没有逻辑意义,但这是查询引擎执行此操作的方式,并且必须始终如一地应用规则。在你的情况下(没有双关语意),你有一个额外的复杂性:区分大小写。 SQL Server在您的子查询中找不到FIELD
,但确实在外部查询中找到了它。所以有几个教训:
答案 1 :(得分:3)
非常有趣的发现。不言而喻的任务是,您总是应该在子查询中对表进行别名,并使用这些别名来明确您的列来自哪个表。子查询允许您引用外部查询中的一个字段,这是导致问题的原因,但在您的方案中,我同意默认值应该是内部查询的字段列表,或者为您提供列歧义错误。无论如何,以下方法总是更可取:
select * from main_table a where a.field in
(select x.field from other_table x)