欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

关于@@rowcountrowcount_big()的更多说明,请查阅msdn:

 

如果影响的结果超过20亿,即整型的最大范围,请使用后者。

邀月注:本文版权由邀月和博客园共同所有,转载请注明出处。