我有这个SQL更改脚本,它作为我的nant orchestrated DB创建或更新的一部分运行:
SET XACT_ABORT ON
BEGIN TRANSACTION
PRINT 'Change MyColumn column to MyNewColumn column in MyTable table'
IF EXISTS (SELECT *
FROM sys.columns
WHERE Name = 'MyColumn' AND Object_id = OBJECT_ID('[dbo].[MyTable]'))
BEGIN
PRINT '-> Exists, change it'
/* NOTE THE NEXT LINE */
SET @Value = (SELECT MyColumn FROM [dbo].[MyTable])
ALTER TABLE [dbo].[MyTable]
DROP CONSTRAINT DF_MyTable_MyColumn
ALTER TABLE [dbo].[MyTable]
DROP COLUMN MyColumn
ALTER TABLE [dbo].[MyTable]
ADD MyNewColumn nvarchar(20) NULL
ALTER TABLE [dbo].[MyTable]
ADD CONSTRAINT DF_MyTable_MyNewColumn DEFAULT ('') FOR MyNewColumn
PRINT '-> Add values back into table'
SET @Dynamic_Sql = 'UPDATE [dbo].[MyTable] SET MyNewColumn = ''' + @Value + ''''
EXEC(@Dynamic_Sql)
PRINT '-> Alter to NOT NULL'
ALTER TABLE [dbo].[MyTable]
ALTER COLUMN MyNewColumn nvarchar(20) NOT NULL
END
ELSE
BEGIN
PRINT '-> Does not exist, skip it'
END
我之前已经运行过此更新脚本并对数据库进行了更改(因此MyColumn不再存在)。但是现在我有了一个新的脚本,但是我的“build”在这个脚本的这一行上失败了:
Msg 207,Level 16,State 1,Line 15 列名称“MyColumn”无效
其中第15行是FROM sys.columns行。但这实际上是抱怨我在IF声明中的行,我在其中放入了NOTE注释。为什么这会是这种行为?当然,如果列名称不再存在,列名将无效。
答案 0 :(得分:2)
创建所有列后是否包含GO批处理分隔符?如果没有,则在第一个查询运行时不会创建列,因为查询解析器会同时解析所有列 - 在解析时,列实际上不存在。
通过添加GO批处理分隔符,您可以强制它解析在实际创建列之后使用新创建的列的查询部分。
答案 1 :(得分:2)
问题(正如Dave Markle暗示,所以随意接受他的回答)是SQL Server解析脚本的整个部分。它看到你指的是MyColumn并且该列不存在,因此它会给你错误。它在IF声明中并不重要。
您可以使用此脚本轻松测试:
CREATE TABLE dbo.Test (my_id int)
GO
IF (1=0)
SELECT blah FROM Test
如果我能找到推迟解析的方法,我会更新这个答案,但除了使用动态SQL之外我不认为你可以。
修改强> 这是一种可能的解决方案。我还没有通过Martin的链接,但那可能是另一个。
CREATE FUNCTION dbo.Get_my_id ()
RETURNS INT
AS
BEGIN
DECLARE @my_id INT
SELECT @my_id = blah FROM dbo.Test
RETURN @my_id
END
GO
CREATE TABLE dbo.Test (my_id INT)
GO
DECLARE @my_id INT
IF (1=0)
SELECT @my_id = dbo.Get_my_id()
GO
顺便说一句,如果你的表中有多行,你会发现你的变量值无法预测,对吗?