sql server 2008提供了一个增强的Sql命令Merge,用法参看MSDN。能根据两张表数据的不同,对两张表进行数据执行插入,更新或删除等操作,一般用在数据的抽取,例如,根据在另一个表中找到的差异在一个表中插入、更新或删除行,可以对两张表数据进行同步。
看例子,假如,有一总产品列表,一个分店产品列表,需要从分店添加产品时更新产品列表。
总产品表,分店产品表结构完全一致:
if OBJECT_ID('Demo_AllProducts')is not null
drop table Demo_AllProductsgo
Create table Demo_AllProducts
(
PKID int not null identity(1,1) primary key,
DName Nvarchar(20) null,
DCode NVarchar(30) null,
DDate datetime null
)
go
创建分店表
if OBJECT_ID('Demo_Shop1_Product') is not null
drop table Demo_Shop1_Product
go
Create table Demo_Shop1_Product
(
PKID int not null identity(1,1) primary key,
DName Nvarchar(20) null,
DCode NVarchar(30) null,
DDate datetime null
)
go
总店录入数据:
Insert into Demo_AllProducts(DName,DCode,DDate)
values
('DemoA','AAA',GETDATE()),
('DemoB','BBB',GETDATE()),
('DemoC','CCC',GETDATE()),
('DemoD','DDD',GETDATE()),
('DemoE','EEE',GETDATE())
1 DemoA AAA 2012-01-29 17:57:34.110
2 DemoB BBB 2012-01-29 17:57:34.110
3 DemoC CCC 2012-01-29 17:57:34.110
4 DemoD DDD 2012-01-29 17:57:34.110
5 DemoE EEE 2012-01-29 17:57:34.110
分店同样的录入数据:
Insert into Demo_Shop1_Product
(DName,DCode,DDate)
values
('DemoA','AAA',GETDATE()),
('DemoB','CCC',GETDATE()),
('DemoF','FFF',GETDATE())
1 DemoA AAA 2012-01-29 18:01:38.797
2 DemoB CCC 2012-01-29 18:01:38.797
3 DemoF FFF 2012-01-29 18:01:38.797
假定现在需要将分店数据完全合并到总产品表中,以编码字段为依据,如果产品名称不一致,则用分店的产品名称替换总产品名称。如果总产品表中不存在,则添加。这里要区分下源表是分店表,目标表是总产品表
可选项:如果分店表中不存在,则从总店表中删除分店中没有的行,如果这样,总产品表和分店表就完全同步了。实际操作中可能不需要删除目标表的行
看语句:
--确定目标表
merge into Demo_AllProducts p
--从数据源查找编码相同的产品
using Demo_Shop1_Product s
on p.DCode=s.DCode
--如果编码相同,则更新目标表的名称
when Matched and p.DName<>s.DName then update set p.DName=s.DName
--如果目标表中不存在,则从数据源插入目标表中
when not Matched by Target then Insert (DName,DCode,DDate) values (s.DName,s.DCode,s.DDate);
--如果数据源的行在源表中不存在,则删除源表行
--when not Matched by source then delete;
执行后结果:
7 DemoA AAA 2012-01-29 18:20:40.477
8 DemoB BBB 2012-01-29 18:20:40.477
9 DemoB CCC 2012-01-29 18:20:40.477
10 DemoD DDD 2012-01-29 18:20:40.477
11 DemoE EEE 2012-01-29 18:20:40.477
12 DemoF FFF 2012-01-29 18:20:48.073
可以看到源表中的数据已经顺利的并入到了目标表中,如果需要记录Merge语句影响的行,可以用output子句,如果仅仅需要知道影响的行数,可以使用@@Rowcount或Rowcount_big(),修改后的实例如下:
--定义表变量以存储输出
Declare @tableVarRecord
Table
(
MPKID int not null identity(1,1) primary key,
PKID int null ,
DName Nvarchar(20) null,
DCode NVarchar(30) null,
DDate datetime null)
--确定目标表
Merge Into Demo_AllProducts p
--从数据源查找编码相同的产品
using Demo_Shop1_Product s
on p.DCode=s.DCode
--如果编码相同,则更新目标表的名称
When Matched and P.DName<>s.DName Then Update set P.DName=s.DName
--如果目标表中不存在,则从数据源插入目标表
When Not Matched By Target Then Insert (DName,DCode,DDate) values (s.DName,s.DCode,s.DDate)
--如果数据源的行在源表中不存在,则删除源表行
When Not Matched By Source Then Delete
OUTPUT deleted.* INTO @tableVarRecord;
----Delete OUTPUT Inserted.* INTO @tableVarRecord;
--返回上个Merge语句影响的行数
select @@ROWCOUNT as Count1,ROWCOUNT_BIG() as Count2
select * from @tableVarRecord;