2013-04-23 103 views
8

我開發的SQL腳本,使用SSMS,這使得在數據庫中的一些變化後:「無效列名稱」錯誤調用時插入表中創建

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;
  • drop Table2;
  • 重新創建Table2,使用新的表模式;
  • Table2中插入一些默認值。

當我試圖執行這個腳本,我得到這些錯誤:

消息207,級別16,狀態1,行262無效列名 '數字'。
消息207,級別16,狀態1,行262無效的列名稱'名稱'。

看起來像SQL Server使用舊架構爲Table2(這的確還沒有這些列),但是這怎麼可能,如果表剛剛用新模式創建?

我在做什麼錯?

服務器版本是SQL Server 2012(SP1) - 11.0.3128.0(X64)。

UPDATE

我已添加PRINT調用(請參閱上面的腳本)。消息窗口中沒有任何內容,除了錯誤消息。所以,腳本沒有被執行......發生了什麼事?

回答

11

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'');') 
+0

感謝您的解釋......這 - 「如果該表已經存在那麼它將按照先前存在的定義進行編譯「 - 是我所能想象到的最愚蠢且不明顯的策略...」GO「不是一個好選擇,腳本比較大,並且有一些變量,在腳本的頂部聲明,在整個腳本中廣泛使用。無論如何,謝謝,我會考慮解決方法。 – Dennis 2013-04-23 10:53:56

+0

@ Dennis如果你不想失去你的變量,那麼我建議將不同的批處理(刪除/創建表)分成不同的存儲過程,然後將它們包裝在主存儲過程中。 – 2013-08-08 01:55:10

相關問題