代码之家  ›  专栏  ›  技术社区  ›  Chris F

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

  •  3
  • Chris F  · 技术社区  · 15 年前

    我有这个SQL变更脚本,它作为NANT协调数据库创建或更新的一部分运行:

    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不再存在)。但是现在我有了一个新的脚本,它出现在这个脚本之后,但是我的“构建”在这个脚本的这一行失败了,原因是:

    消息207,级别16,状态1,第15行 列名称“mycolumn”无效

    其中第15行是FROM sys.columns行。但这实际上是在抱怨我在if语句中的行,在这里我把注释注释放在注释注释中。为什么会这样?当然,如果列名不再存在,它将无效。

    2 回复  |  直到 15 年前
        1
  •  2
  •   Dave Markle    15 年前

    在创建所有列之后,是否包括“执行批处理”分隔符?如果不存在,那么在第一个查询运行时就不会创建列,因为查询分析器同时解析所有列——在解析时,列实际上不存在。

    通过添加Go批处理分隔符,可以强制它解析查询的某些部分,这些部分在实际创建列之后使用新创建的列。

        2
  •  2
  •   Tom H zenazn    15 年前

    问题(正如DaveMarkle所暗示的,请随意接受他的答案)是SQL Server解析脚本的整个部分。它会发现您所指的是mycolumn,而该列不存在,因此它会给出错误。它在if语句中并不重要。

    您可以使用此脚本轻松测试它:

    CREATE TABLE dbo.Test (my_id int)
    GO
    IF (1=0)
        SELECT blah FROM Test
    

    如果我能找到延迟解析的方法,我会更新这个答案,但是除了使用动态SQL之外,我认为您不能。

    编辑: 这里有一个可能的解决方案。我还没看过马丁的链接,但那可能是另一个。

    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
    

    顺便说一句,如果您的表中有多行,您会意识到您的变量的值不能被预测,对吗?