2011-02-28 58 views
21

我正在使用SQL Server 2005/2008。如果它還不存在,我需要向表中添加一列。這將適用於給定數據庫中的所有表。我希望我很接近,但是我遇到了這個解決方案的問題。添加一列,如果它不存在所有表?

這怎麼辦?

這是我有:

EXEC sp_MSforeachtable ' 
    declare @tblname varchar(255); 
    SET @tblname = PARSENAME("?",1); 

    if not exists (select column_name from INFORMATION_SCHEMA.columns 
        where table_name = @tblname and column_name = ''CreatedOn'') 
    begin 
     ALTER TABLE @tblname ADD CreatedOn datetime NOT NULL DEFAULT getdate(); 
    end 
' 

但我得到的錯誤:

錯誤102:附近有語法錯誤@tblname「。 「CreatedOn」附近語法不正確。 「@tblname」附近的語法不正確。 「CreatedOn」附近語法不正確。 ...等,每個表。

+0

可能重複http://stackoverflow.com/questions/1779743/adding-a-column- to-all-user-tables-in-t-sql – JAiro 2011-02-28 18:38:04

+0

@JAiro:這絕對是一個相關的鏈接,但「如果不存在」規則很重要,並且使它更復雜一些。 – 2011-02-28 18:41:00

+0

好,所以你可以用這個完成信息:http://stackoverflow.com/questions/133031/how-to-check-if-column-exists-in-sql-server-table – JAiro 2011-02-28 18:44:40

回答

23

不能使用變量,如@tablename,在DDL。此外,將名稱拼湊成部分並忽略模式只會導致錯誤。您應該只使用「替換在SQL批處理參數,並依靠MSforeachtable替換「?」:的

EXEC sp_MSforeachtable ' 
if not exists (select * from sys.columns 
       where object_id = object_id(''?'') 
       and name = ''CreatedOn'') 
begin 
    ALTER TABLE ? ADD CreatedOn datetime NOT NULL DEFAULT getdate(); 
end'; 
+0

請記住,sp_msforeachtable是不受支持的存儲過程,因此它不應該用於生產代碼。雖然它添加了幾行代碼,但如果使用定義爲從sys.schemas和sys.tables中選擇的**遊標**,則使用的是T-SQL的記錄部分,但您可以選擇影響所有或一些表只通過改變一個WHERE表達式,並且性能是一樣的。此外,如果您使用** quotename **函數,則可以處理的名稱限定符更少。最後,無論您希望如何使用模式/表名,您都有更大的靈活性(例如,用於日誌)。 – 2011-03-01 07:01:57

+0

@PhilHelmer這與一個例子將會有一個很好的答案。 – xr280xr 2017-07-28 14:33:33

4

您需要混合一點動態SQL。這應該工作:

EXEC sp_MSforeachtable ' 
    declare @tblname varchar(255); 
    SET @tblname = PARSENAME("?",1); 
    declare @sql nvarchar(1000); 

    if not exists (select column_name from INFORMATION_SCHEMA.columns 
        where table_name = @tblname and column_name = ''CreatedOn'') 
    begin 
     set @sql = N''ALTER TABLE '' + @tblname + N'' ADD CreatedOn datetime NOT NULL DEFAULT getdate();'' 
     exec sp_executesql @sql 
    end 
' 
+0

如何在不同模式下使用相同名稱的兩個表? 'foo.t'和'bar.t' ... – 2011-02-28 18:53:41

+0

@Remus:是的,如果OP使用模式,那麼這就成了一個問題。 +1給你的答案。 – 2011-02-28 18:56:35

0

也許是這樣的:

EXEC sp_MSforeachtable ' 
    declare @tblname varchar(255); 
    SET @tblname = PARSENAME("?",1); 

    if not exists (select column_name from INFORMATION_SCHEMA.columns 
        where table_name = @tblname and column_name = ''CreatedOn'') 
    begin 
     ALTER TABLE [?] ADD CreatedOn datetime NOT NULL DEFAULT getdate(); 
    end 
' 

甚至是這樣的:

EXEC sp_MSforeachtable ' 
    if not exists (select column_name from INFORMATION_SCHEMA.columns 
        where table_name = ''?'' and column_name = ''CreatedOn'') 
    begin 
     ALTER TABLE [?] ADD CreatedOn datetime NOT NULL DEFAULT getdate(); 
    end 
' 
+2

-1顯然沒有在發佈前測試過。 '[?]'圍繞一個已經括號的名字添加括號,導致'[[schemaname]。[tablename]]'這是不正確的。 – 2011-02-28 18:52:42

+0

@Remus Rusanu:我測試了這個:'sp_MSforeachtable'EXEC sp_help?; EXEC sp_columns?''。這給了一個語法錯誤。然後,我將其更改爲'sp_MSforeachtable'EXEC sp_help [?]; EXEC sp_columns [?]'',它工作(SQL Server 2008 R2)。 – 2011-02-28 19:32:38

+0

...但你沒有測試OP'ALTER TABLE [?]'。 'sp_help'和'sp_columns'都是存儲過程,'?'替換不起作用,因爲'sp_help [foo]。[bar]'是無效的語法。但是'sp_help [[foo]]。[bar]]]'是正確的語法,並且由於參數的處理方式,它實際上結束了工作。 'ALTER TABLE [[foo]]。[bar]]]'雖然不起作用。長話短說:你發佈的代碼沒有通過基本的語法檢查,這可以由任何人驗證。 – 2011-02-28 20:05:46

相關問題