【问题标题】:"Invalid column name" error when calling insert after table created创建表后调用插入时出现“无效的列名”错误
【发布时间】:2013-04-16 11:00:03
【问题描述】:

我正在使用 SSMS 开发 SQL 脚本,它会对数据库进行一些更改:

USE MyDatabase;

BEGIN TRANSACTION;

-- some statements

PRINT(N'#1');

IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = N'dbo' AND TABLE_NAME = N'Table1' AND COLUMN_NAME = 'Table2_Id'))
BEGIN
    ALTER TABLE [dbo].[Table1] DROP CONSTRAINT [FK_Table1_Table2_Table2_Id];
    ALTER TABLE [dbo].[Table1] DROP COLUMN [Table2_Id];
    DROP TABLE [dbo].[Table2];

    PRINT(N'Table2 was dropped.');
END

PRINT(N'#2');

IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = N'dbo' AND TABLE_NAME = N'Table2'))
BEGIN
    CREATE TABLE [dbo].[Table2]
    (
        [Id] INT NOT NULL PRIMARY KEY IDENTITY,
        [Number] INT NOT NULL UNIQUE,
        [Name] NVARCHAR(200) NOT NULL,
        [RowVersion] TIMESTAMP NOT NULL
    );
PRINT(N'Table2 was re-created.');
    INSERT INTO [dbo].[Table2]([Number], [Name]) VALUES(-1, N'Default value');
PRINT(N'Default value was inserted in Table2.');
END

-- some statements

COMMIT TRANSACTION;

如果Table1 有一个名为Table2_Id 的列,则数据库有两个表(Table1Table2)以及它们之间的外键关系。在这种情况下,我需要:

  • 删除外键关系FK_Table1_Table2_Table2_Id;
  • 删除外键列Table1.Table2_Id;
  • 删除Table2;
  • 使用新表架构重新创建Table2
  • Table2 中插入一些默认值。

当我尝试执行此脚本时,出现以下错误:

消息 207,级别 16,状态 1,第 262 行无效的列名称“数字”。
消息 207,级别 16,状态 1,第 262 行无效的列名称“名称”。

看起来 SQL Server 对 Table2 使用旧架构(确实没有这些列),但如果表刚刚使用新架构创建,这怎么可能?

我做错了什么?

服务器版本为 SQL Server 2012 (SP1) - 11.0.3128.0 (X64)。

更新

我添加了PRINT 调用(参见上面的脚本)。消息窗口中没有任何内容,除了错误消息。所以,脚本没有被执行……这是怎么回事??

【问题讨论】:

    标签: sql-server sql-server-2012-express


    【解决方案1】:

    SQL Server 尝试编译整个批处理。如果表已经存在,那么它将根据预先存在的定义进行编译。引用新列的语句不会编译,因此批处理永远不会执行。

    您需要将使用新定义的语句分组到一个新批次中。如果您在 SSMS 中运行它,只需插入 GO

    USE MyDatabase;
    
    BEGIN TRANSACTION;
    
    -- some statements
    
    PRINT(N'#1');
    
    IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = N'dbo' AND TABLE_NAME = N'Table1' AND COLUMN_NAME = 'Table2_Id'))
    BEGIN
        ALTER TABLE [dbo].[Table1] DROP CONSTRAINT [FK_Table1_Table2_Table2_Id];
        ALTER TABLE [dbo].[Table1] DROP COLUMN [Table2_Id];
        DROP TABLE [dbo].[Table2];
    
        PRINT(N'Table2 was dropped.');
    END
    
    GO
    
    PRINT(N'#2');
    
    IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = N'dbo' AND TABLE_NAME = N'Table2'))
    BEGIN
        CREATE TABLE [dbo].[Table2]
        (
            [Id] INT NOT NULL PRIMARY KEY IDENTITY,
            [Number] INT NOT NULL UNIQUE,
            [Name] NVARCHAR(200) NOT NULL,
            [RowVersion] TIMESTAMP NOT NULL
        );
    PRINT(N'Table2 was re-created.');
        INSERT INTO [dbo].[Table2]([Number], [Name]) VALUES(-1, N'Default value');
    PRINT(N'Default value was inserted in Table2.');
    END
    
    COMMIT
    

    否则,您可以在子批次中运行违规行

        EXEC(N'INSERT INTO [dbo].[Table2]([Number], [Name]) VALUES(-1, N''Default value'');')
    

    【讨论】:

    • 感谢您的解释......这 - “如果表已经存在,那么它将根据预先存在的定义进行编译” - 是我能想象的最愚蠢且不明显的策略...... . GO 不是一个好选择,脚本相当大,并且有一些变量,声明在脚本顶部,在整个脚本中广泛使用。无论如何,谢谢,我会考虑解决方法。
    • @Dennis 如果您不想丢失变量,那么我建议将不同的批次(删除/创建表)拆分为单独的存储过程,然后将它们包装在主存储过程中。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 2021-10-07
    • 2021-07-18
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多