1

使用 SQL Server Management Studio,我得到了一些不想要的结果(对我来说看起来像一个错误..?)

如果我使用(字段而不是 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

我收到无效的列名错误。

当然我应该在第一种情况下得到这个错误?

这与整理有关吗?数据库是二进制排序规则。但是,服务器不区分大小写。在我看来,服务器组件在说“这段代码没问题”,并且不允许数据库说该字段是错误的名称..?

我的解决方案有哪些选择?

4

2 回答 2

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. 始终使用表名或别名作为列引用的前缀(并始终在表引用前加上 schema)。
  2. 始终使用一致的大小写创建和引用您的表、列和其他实体。特别是在使用二进制或区分大小写的排序规则时。
于 2012-06-01T12:17:26.307 回答
3

非常有趣的发现。不言而喻的要求是,您始终应该为子查询中的表设置别名,并使用这些别名来明确说明您的列来自哪个表。子查询允许您从外部查询中引用一个字段,这是您的问题的原因,但在您的场景中,我同意默认值应该是内部查询的字段列表,或者给您一个列歧义错误。无论如何,下面的这种方法总是更可取的:

select * from main_table a where a.field in (select x.field from other_table x)

于 2012-06-01T11:54:20.480 回答