2013-03-13 57 views
4

我正在從我的web應用程序中執行SQLBulkCopy並將記錄插入臨時表中。這是我第一次處理登臺表。將接受數據的實時表格有大約200個字段,可以轉換到未來。當發生這種變化時,我不想重新編寫合併語句。沒有指定列名的SQL合併功能

我想出了這個模仿合併功能的SQL,但並不要求我拼出表列。我不是一位SQL專家,並且希望某個人能夠查看並讓我知道是否看到使用此SQL可能會出現的任何問題,因爲我沒有看到有關此搜索和許多人搜索的任何示例。

請注意,臨時表中具有空id域的記錄將被插入。

-- set the table names, primary key field & vars to hold query parts 
DECLARE @LiveTable varchar(20) = 'Test' 
DECLARE @StagingTable varchar(20) = 'TestStaging' 
DECLARE @PKField varchar(20) = 'TestPK' 
DECLARE @SQLSet nvarchar(MAX) = '' 
DECLARE @SQLInsertFields nvarchar(MAX) = '' 

-- get comma delimited field names 
DECLARE @Fields nvarchar(MAX) = (SELECT dbo.fn_GetCommaDelimitedFieldNames(@LiveTable)) 

-- loop through fields generating set clause of query to execute 
WHILE LEN(@Fields) > 0 
BEGIN 
    DECLARE @Field varchar(50) = left(@Fields, CHARINDEX(',', @Fields+',')-1) 
    IF @Field <> @PKField -- the primary key field cannot be updated 
     BEGIN 
      SET @SQLSet += ', ' + @LiveTable + '.' + @Field + ' = ' + @StagingTable + '.' + @Field 
      SET @SQLInsertFields += ', ' + @Field 
     END 
    SET @Fields = STUFF(@Fields, 1, CHARINDEX(',', @Fields+','), '') 
END 

-- remove the leading comma 
SET @SQLSet = SUBSTRING(@SQLSet,3,LEN(@SQLSet)) 
SET @SQLInsertFields = SUBSTRING(@SQLInsertFields,3,LEN(@SQLInsertFields)) 

-- update records from staging table where primary key is provided 
DECLARE @SQL nvarchar(MAX) = N'UPDATE ' + @LiveTable + 
          ' SET ' + @SQLSet + 
          ' FROM ' + @LiveTable + 
          ' INNER JOIN ' + @StagingTable + 
          ' ON ' + @LiveTable + '.' + @PKField + ' = ' + @StagingTable + '.' + @PKField 

-- insert records from staging table where primary key is null 
SET @SQL += '; INSERT INTO ' + @LiveTable + ' (' + @SQLInsertFields + ') SELECT ' + @SQLInsertFields + ' FROM ' + @StagingTable + ' WHERE ' + @PKField + ' IS NULL' 

-- delete the records from the staging table 
SET @SQL += '; DELETE FROM ' + @StagingTable 

-- execute the sql statement to update existing records and insert new records 
exec sp_executesql @SQL; 

如果任何人看到任何與表演或其他任何問題,我欣賞洞察力。

+2

您可能希望將其作爲事務執行,以便在插入或更新時不會出現錯誤,然後刪除臨時表。 – Hogan 2013-03-13 02:43:22

+0

@霍根 - 好點,肯定會投入交易。感謝您的輸入。 – Ricketts 2013-03-13 02:48:54

+0

200個字段在一個表中?是關係型還是平面文件? – 2013-03-13 02:49:30

回答

0

不要這樣做。真。你正在努力避免一個罕見的問題,當時間到了的時候你可能無法正確處理。

如果目標表發生變化,您如何知道它將以這樣的方式發生變化,以致您的花哨動態SQL可以正常工作?你怎麼能確定它不會似乎工作 - 即將工作,語法上 - 但實際上做錯了什麼?如果當目標表發生更改時,是否必須更改應用程序和臨時表?隨着所有這些在空中,什麼是增加一個SET子句?

與此同時,如何能期望任何人閱讀gobbledygook(不是你的錯,真的,這是SQL的語法)?一個bog標準的插入語句將非常清晰可靠。

而且速度很快。 SQL Server無法優化您的動態查詢。你使用bcp來提高效率,現在你可以很好地打敗未來。

+0

感謝您的意見,我們將對此予以高度考慮。我會測試這個與MERGE的性能,如果有很大的差異,我會走這條路線並手動保持MERGE語句。我無法想象這種情況無法正確執行,也許你可以提供一個例子嗎?有一個觸發器可以保持暫存表結構與目標表同步,因此在那裏不存在問題。如果目標表發生變化,我的應用程序中唯一的變化就是更新EntityModel,但不會更改代碼,因爲源代碼的映射是動態的。 – Ricketts 2013-03-14 04:10:32