查询不存在的列不会失败

时间:2012-03-27 10:29:10

标签: sql sql-server sql-server-2008

奇怪的情况。

如果我有这些表格:

CREATE TABLE t1 (id INT, title VARCHAR(20), someIntCol INT)
GO
CREATE TABLE t2 (id INT, t1Id INT, someData VARCHAR(20))
GO

并且做:

SELECT    t1.* 
FROM    t1 
WHERE    t1.id IN (SELECT someIntCol FROM t2)
奇怪的是:解析器并不介意列someIntCol不存在

奇怪的是:如果我将someIntCol更改为someIntCol2,我会得到一个“无效的列名'someIntCol2'。”错误

任何人都可以解释一下吗?

仅供参考,这不是我的代码。我是从this链接

获得的

4 个答案:

答案 0 :(得分:6)

尝试:

SELECT    t1.* 
FROM    t1 
WHERE    t1.id IN (SELECT t2.someIntCol FROM t2)

这将在执行时抛出异常。

由于someIntCol中存在t1,因此它正在使用主查询中的该数据项。

子查询能够使用主查询中的数据项。因此,为避免这种情况,请在输入数据项时指定表名:

SELECT [TableName].[ColumnName]

如果您在t1t2

中有2个具有相同名称的列,这也可以防止出现歧义

这是一个MSDN,它可以让您更好地理解子查询的工作原理:

http://msdn.microsoft.com/en-us/library/aa213262(v=sql.80).aspx

答案 1 :(得分:4)

在SQL Server中,解析步骤仅在语义上检查语法,例如以数字开头的非转义列,例如[2ndColumn]而不是2ndColumn(解析失败),关键字等,以及制作确保查询可以解析。这是单击SSMS中的解析按钮时发生的过程。此过程不会针对基础数据验证查询。

因此我可以键入SELECT abc FROM DEF,即使我没有任何名为abc的列,甚至没有名为DEF的表。

下一步是algebrizer,它是绑定的过程。此步骤(仅在解析查询时不会发生)确保查询的每个对象实际存在,并且在您引用不存在的对象时将失败。

验证这一点的另一种方法是告诉SQL Server只解析,而不是做任何其他事情:

SET PARSEONLY ON
SELECT abc FROM def
GO

上面的查询会说“命令已成功执行。”

SET PARSEONLY OFF
SELECT abc FROM def
GO

上面的查询会说“无效的对象名称'def'。”

在您的示例问题中,someIntCol列存在于查询范围内,因为您尚未从中指定特定的来源。结果并没有多大意义,但它仍然不是一个无效的查询。

答案 2 :(得分:1)

Parser不介意因为他在t1中“看到”列someIntCol。你没有指定从哪个表中取出someIntCol所以解析器“假设”你想要它来自t1。

答案 3 :(得分:0)

你能找到吗

SELECT    t1.*  FROM    t1  WHERE    t1.id IN (SELECT someIntCol FROM t2)

表T2没有列“someIntCol”。

所以解析器显示错误