2013-11-26 60 views
0

如何從SQL Server臨時表中刪除列(如果存在於列表中)?基於CSV輸入參數從#temp表中刪除列

喜歡的東西:

DECLARE @cols AS NVARCHAR(MAX) 
    @cols will have value like [first_name], [last_name], ..... 
    So @cols = '[first_name], [last_name], .....' 

現在

ALTER TABLE #my_tables 
    DROP COLUMN @cols 

如何檢查是否#my_tables確實含有last_name與否?如果不是忽略它而不是拋出錯誤。我仍然需要刪除@cols中存在的其他列

我認爲如果個別列上存在條件,我們可以做。

感謝

+1

你爲什麼要麻煩從#temp表中刪除列?只要忽略它們。 –

+0

,因爲我需要追加相同的列和值從另一個動態樞軸值 – user1882705

+1

所以,爲什麼你不等待構建#temp表,直到你知道所有的列將是什麼?或者只是命名新列first_name2,last_name2等?或者首先避免#temp表?你知道你將有一段時間鞏固範圍,試圖構建和更改#temp表,同時還需要使用動態SQL ... –

回答

3

我狡猾DBA同意:你應該在路過這些值作爲一個表值參數,而不是以逗號分隔的列表。但這並不能真正改變問題:您仍然要動態生成所有DROP COLUMN命令,無論列名是使用表值函數從CSV解析的,還是從TVP拉取的。

我會繼續使用逗號分隔列表的當前需求。

首先,創建一個字符串拆分函數。這是我使用的一個:

CREATE FUNCTION [dbo].[SplitString] 
    (
     @List NVARCHAR(MAX), 
     @Delim VARCHAR(255) 
    ) 
    RETURNS TABLE 
    AS 
     RETURN (SELECT [Value] FROM 
      ( 
      SELECT 
       [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number], 
       CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number]))) 
      FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name) 
       FROM sys.all_objects) AS x 
       WHERE Number <= LEN(@List) 
       AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim 
     ) AS y 
     ); 
GO 

現在,創建一個愚蠢的#TEMP表:

CREATE TABLE #foo(id INT, x INT); 

現在,你可以宣佈你想嘗試刪除列的列表,創建一個動態SQL來檢查,他們投下他們之前存在,然後語句刪除它可以將那些:

DECLARE @cols VARCHAR(MAX); 
SET @cols = '[first_name], [last_name], [id]'; 

DECLARE @sql NVARCHAR(MAX); 
SET @sql = N''; 

SELECT @sql = @sql + N'IF EXISTS (SELECT 1 FROM tempdb.sys.columns AS c 
    WHERE [object_id] = OBJECT_ID(''tempdb..#foo'') 
    AND name = ' + REPLACE(REPLACE(QUOTENAME(s.Value, ''''),']',''),'[','') + ') 
    ALTER TABLE #foo DROP COLUMN ' + s.Value + ';' 
FROM dbo.SplitString(@cols, ',') AS s; 

EXEC sp_executesql @sql; 

SELECT * FROM #foo; -- this only returns the column x 

如果再次運行這部分代碼,對同一個表,它會運行沒有錯誤。您可能遇到的一些錯誤是:

  • 如果您嘗試刪除參與任何約束(默認,PK,FK,檢查等)的列。
  • 如果您嘗試刪除表中的最後一列。
  • 如果您的列名稱選擇非常差,以某種方式繞過了我試圖在此列入的所有保護措施。
+0

感謝您的明確解決方案。我認爲現在這對我來說很有用。這裏我的實際情況是:我有一個用戶表和相應的事務表,它存儲了所有隨時間修改的字段名稱及其先前的數據和更新的數據(我在此使用觸發器)。所以我在這裏要做的是獲取從事務表和其餘字段從用戶表中修改的字段,並返回所有值作爲輸出geother作爲輸出 – user1882705

+0

如果你不介意我可以給你的代碼是什麼我我正試圖做現在。請幫我寫出最有效的商店流程。我知道我問的太多了,但這會幫助我完成我的完整項目。 – user1882705

0

使用此:

SELECT * 
FROM information_schema.COLUMNS 
WHERE 
    TABLE_SCHEMA = 'db_name' 
AND TABLE_NAME = 'table_name' 
AND COLUMN_NAME = 'column_name' 

它會返回列是否存在,可以從該SQL響應,以決定是否或不做瓶坯下降

1

你可以只是使用動態SQL;但是,請注意SQL注入。

我會將@cols作爲參數傳遞給存儲過程。

程序的主體將在下面。

-- Declare local variables 
DECLARE @STMT NVARCHAR(MAX); 

-- Create the stmt 
SET @STMT = 'ALTER TABLE #my_tables DROP COLUMN ' + @cols; 

-- Execute the stmt 
EXEC sp_executesql @STMT; 

我寧願傳遞一個表值參數,但那只是我。

+0

我已經在使用動態查詢,但是當@cols包含就像列表中的[Address]一樣,它存在於臨時表中,然後拋出錯誤。 – user1882705

+0

ALTER TABLE DROP COLUMN失敗,因爲列'地址'不存在於表'#my_tables – user1882705

+0

@AaronBertrand,我的臨時表#my_tables不包含該地址列,但我的'@cols'包含該地址作爲昏迷分隔字段之一。 – user1882705

1

檢查你需要記住的是一個臨時表中的列被它存儲在臨時數據庫

select * 
from tempdb.sys.columns 
where object_id = object_id('tempdb..#my_tables')