为什么现有列的测试在SQL中失败?

时间:2010-08-13 16:52:42

标签: sql sql-server

我有这个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注释。为什么这会是这种行为?当然,如果列名称不再存在,列名将无效。

2 个答案:

答案 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

顺便说一句,如果你的表中有多行,你会发现你的变量值无法预测,对吗?