SQLServer 2008中SQL增强之三 Merge(在一条语句中使用Insert,Update,Delete)
程序员文章站
2023-09-06 20:13:05
sql server 2008提供了一个增强的sql命令merge,用法参看msdn:
功能:根据与源表联接的结果,对目标表执行插入、更新或删除操作。例如,根据在另一个表...
sql server 2008提供了一个增强的sql命令merge,用法参看msdn:
功能:根据与源表联接的结果,对目标表执行插入、更新或删除操作。例如,根据在另一个表中找到的差异在一个表中插入、更新或删除行,可以对两个表进行同步。
我们看一个例子,假如,有一总产品列表,一个分店产品列表,需要从分店添加产品时更新总产品列表。
总产品表,分店产品表结构完全一致:
复制代码 代码如下:
if object_id('demo_allproducts') is not null
drop table demo_allproducts
go
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
--this sql is only for sql server 2008
insert into demo_allproducts
(dname,dcode,ddate)
values
('demoa','aaa',getdate()),
('demob','bbb',getdate()),
('democ','ccc',getdate()),
('demod','ddd',getdate()),
('demoe','eee',getdate())
select * from demo_allproducts
--pkid dname dcode ddate
--1 demoa aaa 2010-10-12 20:33:54.417
--2 demob bbb 2010-10-12 20:33:54.417
--3 democ ccc 2010-10-12 20:33:54.417
--4 demod ddd 2010-10-12 20:33:54.417
--5 demoe eee 2010-10-12 20:33:54.417
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
--this sql is only for sql server 2008
insert into demo_shop1_product
(dname,dcode,ddate)
values
('demoa','aaa',getdate()),
('demob','ccc',getdate()),
('demof','fff',getdate())
select * from demo_shop1_product
--pkid dname dcode ddate
--1 demoa aaa 2010-10-17 20:19:32.767
--2 demob ccc 2010-10-17 20:19:32.767
--3 demof fff 2010-10-17 20:19:32.767
假定现在需要将分店数据完全合并到总产品表中,以编码字段为依据,如果产品名称不致,则用分店的产品名称替换总产品名称。
如果总产品表中不存在,则添加。
可选项:如果分店表中不存在,则从总产品表中删除分店中没有的行。如果这样,总产品表和分店表就完全同步了。实际操作中可能不需要删除目标表的行。
语句如下:
复制代码 代码如下:
--确定目标表
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;
此时,执行完成后,两个表的行均如下:
复制代码 代码如下:
--pkid dname dcode ddate
--1 demoa aaa 2010-10-17 20:31:00.827
--2 demob ccc 2010-10-17 20:31:00.827
--3 demof fff 2010-10-17 20:31:00.827
如果不删除,语句如下:
复制代码 代码如下:
--确定目标表
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);
执行后结果:
复制代码 代码如下:
--pkid dname dcode ddate
--1 demoa aaa 2010-10-17 20:30:28.350
--2 demob bbb 2010-10-17 20:30:28.350
--3 demob ccc 2010-10-17 20:30:28.350
--4 demod ddd 2010-10-17 20:30:28.350
--5 demoe eee 2010-10-17 20:30:28.350
--6 demof fff 2010-10-17 20:31:00.827
--pkid dname dcode ddate
--1 demoa aaa 2010-10-17 20:31:00.827
--2 demob ccc 2010-10-17 20:31:00.827
--3 demof fff 2010-10-17 20:31:00.827
如果需要记录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;
结果:
复制代码 代码如下:
--影响的行数
--count1 count2
--5 5
--deleted表的行
--mpkid pkid dname dcode ddate
--1 null null null null
--2 2 demob bbb 2010-10-17 21:42:30.700
--3 3 democ ccc 2010-10-17 21:42:30.700
--4 4 demod ddd 2010-10-17 21:42:30.700
--5 5 demoe eee 2010-10-17 21:42:30.700
关于@@rowcount和rowcount_big()的更多说明,请查阅msdn:
如果影响的结果超过20亿,即整型的最大范围,请使用后者。