我在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。
这有什么理由吗?这是我的代码吗?
答案 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的评论:你为什么编写无效代码,然后抱怨它被误认为有效?