如果我尝试执行以下代码,则会收到错误
消息207,级别16,状态1,行3无效的列名称“另一个”。消息 207,级别16,状态1,行4无效的列名称“另一个”。
即使两个IF
语句的谓词总是计算为false。
CREATE TABLE #Foo (Bar INT)
GO
IF (1=0)
BEGIN
SELECT Another FROM #Foo
END
GO
IF (1=0)
BEGIN
ALTER TABLE #Foo ADD Another INT
SELECT Another FROM #Foo
END
GO
DROP TABLE #Foo
为了这个例子,这可能过于简化了;实际上我需要做的是从列中选择值,但仅在列存在时才选择。如果它不存在,我不关心它。在驱使我提出这个问题的问题中,我的谓词与EXISTS (SELECT * FROM sys.columns WHERE object_id = @ID AND name = @Name)
一致。有没有办法实现这一点,而不诉诸我的敌人动态SQL?我知道我的SQL必须始终是格式良好的(即符合语法) - 即使在一个从未执行过的块中 - 但我也大惊小怪,我也被迫使它在语义上也正确!
修改: 虽然我不确定下面的代码对上面的代码增加了很多,但它是问题的另一个例子。在这种情况下,我只想设置绝对值(绝对存在为列)的值,如果Maybe存在,则可以使用Maybe(可能作为列存在)中的值。
IF EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('dbo.TableName', 'U') AND name = 'Maybe')
BEGIN
UPDATE dbo.TableName SET Definitely = Maybe
END
答案 0 :(得分:7)
SQL Server不会逐行执行。它不像.net或Java代码那样是过程。所以没有“非执行块”
批处理一次编译。此时,该列不存在,但它知道该表将是。表没有名为“Another”的列。失败。
完全符合预期。
现在,您要解决的真正问题是什么?
一些选项:
评论后编辑;
为什么不隐藏视图后面的架构更改,而不是更改所有代码以使用可能/可能不存在的列?
答案 1 :(得分:4)
您可以使用EXEC
来处理它。如果代码永远不会真正改变,那它就不是真正的动态SQL。
例如:
CREATE TABLE dbo.Test (definitely INT NOT NULL)
INSERT INTO dbo.Test (definitely) VALUES (1), (2), (3)
IF EXISTS (SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.Test', 'U') AND
name = 'Maybe')
BEGIN
EXEC('UPDATE dbo.Test SET definitely = maybe')
END
SELECT * FROM dbo.Test
ALTER TABLE dbo.Test ADD maybe INT NOT NULL DEFAULT 999
IF EXISTS (SELECT *
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.Test', 'U') AND
name = 'Maybe')
BEGIN
EXEC('UPDATE dbo.Test SET definitely = maybe')
END
SELECT * FROM dbo.Test
DROP TABLE dbo.Test
答案 2 :(得分:2)
您还可以尝试使用不存在的表格Martin Smith's“解决方法”来获取列的“延迟名称解析”。
答案 3 :(得分:1)
我有同样的问题。 我们多年来为所有更改创建了一个脚本,这是我们第一次遇到此问题。 我已经尝试了你所有的答案,但没有找到问题。
在我的情况下,这是因为脚本中的临时表我也在存储过程中使用,尽管每个句子都已经去了。 我发现,如果我在脚本使用临时表后添加了临时表,那么它是正确的。
祝你好运, 陈
答案 4 :(得分:1)
来自@gbn的答案。 我要解决的问题是在ALTER查询和使用ALTER添加的列的查询之间使用'GO'。这将使这两个查询分别作为批处理运行,从而确保SELECT查询之前位于“另一”列。