我每周都会收到一个CSV文件,我使用BULK INSERT导入我的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 :(得分:1)
merge语句有output clause,它会将受影响的行输出到表中,或者作为查询的结果。
您还可以在匹配时部分指定额外条件。在这种情况下,如果所有值都与现有行相同,则使用它来确保不会更新行。如果列可以为空,那么这很麻烦,因为(1 != Null)
会返回Null
。对于您的评分,我假设不能为负,您可以IsNull(s.rating, -1) != IsNull(t.rating, -1)
查看是否已更改
由于output子句可以是查询的结果,因此可以将其嵌套为内部查询。我已使用此功能将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