2012-11-23 52 views
2

我每週收到一個CSV文件,該文件使用BULK INSERT導入到我的SQL數據庫中。我插入到臨時表中,然後通過插入新記錄並更新任何已修改的記錄,將其與主表合併。該代碼是:批量插入後的SQL觸發器

BULK INSERT dbo.temp 
FROM 'C:\Users\Administrator\Documents\20120125.csv' 
WITH (FIELDTERMINATOR = ',', ROWTERMINATOR = '\n'); 

MERGE dbo.main AS TargetTable        
USING dbo.temp AS SourceTable      
ON (TargetTable.name = SourceTable.name)     
WHEN NOT MATCHED BY TARGET        
    THEN INSERT (name, age, gender, father, mother, teacher, mathsrating, historyrating, sciencerating, englishrating) 
     VALUES(SourceTable.name, SourceTable.age, SourceTable.gender, SourceTable.father, SourceTable.mother, SourceTable.teacher, SourceTable.mathsrating, SourceTable.historyrating, SourceTable.sciencerating, SourceTable.englishrating) 
WHEN MATCHED            
    THEN UPDATE SET 
     TargetTable.name = SourceTable.name, 
     TargetTable.age = SourceTable.age, 
     TargetTable.gender = SourceTable.gender, 
     TargetTable.father = SourceTable.father, 
     TargetTable.mother = SourceTable.mother, 
     TargetTable.teacher = SourceTable.teacher, 
     TargetTable.mathsrating = SourceTable.mathsrating, 
     TargetTable.historyrating = SourceTable.historyrating, 
     TargetTable.sciencerating = SourceTable.sciencerating, 
     TargetTable.englishrating = SourceTable.englishrating; 

DELETE FROM dbo.temp 

我想達到什麼是具有由存儲在與他們的「上一個」值的新表,讓我有什麼改變了歷史的更新覆蓋的記錄。我對SQL相當陌生,但研究了一些似乎觸發器可能是採取的方法,但會歡迎任何有關如何解決此問題的建議。

感謝

馬特

+0

是的,對不起,這是SQL Server 2012的 – MrMatt

回答

1

MERGE語句有一個output clause將輸出受影響的行要麼表,或作爲查詢的結果。

您還可以在匹配部分中指定額外條件。在這種情況下,如果所有值都與現有行相同,請使用它確保行不會更新。如果列可以爲空,這是非常棘手的,因爲(1 != Null)返回Null。爲了您的評分,我假設不能否定,您可以執行IsNull(s.rating, -1) != IsNull(t.rating, -1)以查看它是否已更改

由於輸出子句可以是查詢的結果,因此可以將其嵌套爲內部查詢。我已經使用它將UpdateTimestamp添加到歷史記錄表中。

舉例:爲什麼空檢查是必要的http://sqlfiddle.com/#!6/1651a/2

例子:http://sqlfiddle.com/#!6/bd99b/2

Insert Into 
    history_table 
Select 
    GetDate(), [name], age, gender, father, mother, teacher, 
    mathsrating, historyrating, sciencerating, englishrating 
From (
    Merge 
    dbo.main As t 
    Using 
    dbo.temp AS s 
     On (t.[name] = s.[name]) 
    When Not Matched By Target Then 
    Insert (
     [name], age, gender, father, mother, teacher, 
     mathsrating, historyrating, sciencerating, englishrating 
    ) values (
     s.[name], s.age, s.gender, s.father, s.mother, s.teacher, 
     s.mathsrating, s.historyrating, s.sciencerating, s.englishrating 
    ) 
    When Matched And -- assume ratings can't be negative, but can be null 
    t.age != s.age Or 
    t.gender != s.gender Or 
    t.father != s.father Or 
    t.mother != s.mother Or 
    t.teacher != s.teacher Or 
    IsNull(t.mathsrating, -1) != IsNull(s.mathsrating, -1) Or 
    IsNull(t.historyrating, -1) != IsNull(s.historyrating, -1) Or 
    IsNull(t.sciencerating, -1) != IsNull(s.sciencerating, -1) Or 
    IsNull(t.englishrating, -1) != IsNull(s.englishrating, -1) 
    Then Update 
    Set 
     t.[name] = s.[name], 
     t.age = s.age, 
     t.gender = s.gender, 
     t.father = s.father, 
     t.mother = s.mother, 
     t.teacher = s.teacher, 
     t.mathsrating = s.mathsrating, 
     t.historyrating = s.historyrating, 
     t.sciencerating = s.sciencerating, 
     t.englishrating = s.englishrating 
    Output 
     $action as Action, deleted.* 
) as Updates 
+0

感謝您的答覆。我試過,但history_table返回0行。我使用dbo.main和dbo.temp中的相同列創建了history_table - 這是您的意思嗎? – MrMatt

+0

這就是我的意思。這裏提到的輸出表有一些限制:http://technet.microsoft.com/en-us/library/ms177564.aspx特別是,沒有觸發器,沒有外鍵和檢查限制。另外,如果您有標識列或計算列,則可能需要明確指定列。 – Laurence

+0

謝謝。它返回0行的原因是我在主桌上留下了一個觸發器,而我正在試驗這個。現在刪除觸發器會返回行,但它不像預期的那樣工作。歷史記錄表包含與臨時表完全相同的行數。 – MrMatt