SQL Temp表没有抛出无效的列名称错误

时间:2011-08-15 21:03:49

标签: tsql sql-server-2008

我在SQL Server 2008 Management Studio中发现了以下问题。当我整个运行以下脚本时,我预计会出现错误(由于“复制和粘贴错误”),但是不会收到错误。

IF OBJECT_ID('Foo') IS NOT NULL
BEGIN
    DROP TABLE Foo
END
IF OBJECT_ID('Bar') IS NOT NULL
BEGIN
    DROP TABLE Bar
END
CREATE TABLE Foo (
    FooID int
)
Create Table Bar (
    BarID int
,   FooID int
)
INSERT INTO Foo
SELECT 1 UNION ALL SELECT 2
INSERT INTO Bar
SELECT 1,1 UNION ALL SELECT 2,1 UNION ALL SELECT 3,1
GO

IF OBJECT_ID('tempdb..#temp') IS NOT NULL
BEGIN
      DROP TABLE #TEMP
END
GO
CREATE TABLE #TEMP (
    FooID int
)
INSERT INTO #TEMP
    SELECT FooID FROM Bar
GO
SELECT * FROM Foo WHERE FooID IN (SELECT FooID FROM #TEMP)
GO
SELECT * FROM Bar WHERE BarID IN (SELECT BarID FROM #TEMP)
GO
SELECT * FROM #TEMP
GO

运行包含“SELECT BarID FROM #TEMP”上的where子句过滤的第二个最后一个语句,但#TEMP中没有BarID列。当整个脚本运行时,我没有收到任何错误,脚本返回Foo中的所有行。但是,当我自己运行命令时,我收到错误通知我#TEMP中没有BarId。

这有什么理由吗?这是我的代码吗?

2 个答案:

答案 0 :(得分:4)

您的倒数第二个查询实际上正常运行。

其他评论者请指正,但我理解这是一个相关的子查询。表别名将显示实际发生的情况。您的查询等同于:

SELECT * FROM Bar x WHERE x.BarID IN (SELECT x.BarID FROM #TEMP)

对于#TEMP中的每一行,嵌套的select实际上是从表Bar返回BarID的当前值,所以是的,(BarID)中的BarID为true,因此Bar中的每一行都匹配,因此返回每一行。

要表明你并不疯狂,请尝试

SELECT * FROM Bar WHERE BarID IN (SELECT NonExistentFieldName FROM #TEMP) 

这引发了我认为你期待的错误。

答案 1 :(得分:0)

有关Neil答案的一些背景信息,请参阅以下知识库文章:

http://support.microsoft.com/kb/298674

他们使用的示例(虽然看起来不应该有效)与您的示例非常相似(尽管没有#temp表):

CREATE TABLE X1 (ColA INT, ColB INT)
CREATE TABLE X2 (ColC INT, ColD INT)
SELECT ColA FROM X1 WHERE ColA IN (Select ColB FROM X2)

他们还表明添加表别名(由于许多原因这是一个很好的做法,但会阻止此问题通过编译)会使查询失败,因为您最初的预期。

这实际上是遵循ANSI标准的列分辨率,并且不会改变(除非它们实现了Erland的SET STRICT_CHECKS ON)。

其他一些抱怨过这个错误的人(还有更多关于引擎必须以这种方式工作的背景):

http://connect.microsoft.com/SQL/feedback/details/542289/

http://connect.microsoft.com/SQL/feedback/details/422252/

http://connect.microsoft.com/SQL/feedback/details/126785/

必须同意@ BalamBalam的评论:你为什么编写无效代码,然后抱怨它被误认为有效?

相关问题