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;