SQL Server2008 Merge应用实例(Merge执行统计库存,复制表,输出$action列 ,output...INTO..)

时间:2021-06-18 17:16:49
--SQL Server2008 Merge应用实例 

/********************************************************************************
*主题:SQL Server2008 Merge应用实例
*说明:本文是个人学习的一些笔记和个人愚见
* 有很多地方你可能觉得有异议,欢迎一起讨论

*作者:Stephenzhou(阿蒙)
*日期: 2012.12.5

*Mail:szstephenzhou@163.com
*另外:转载请著名出处。
**********************************************************************************/


先不解释 看实例吧

有两个表如下

 

 

if OBJECT_ID('Stock') is not null
drop table Stock
go
create table Stock (Symbol varchar(10) primary key,Qty int check(Qty>0))
if OBJECT_ID('Trade') is not null
drop table Trade
go
create table Trade (Symbol varchar(10) primary key,Delta int check(Delta<>0))

--两个表,第一个表Stock为库存表 ,Trade为交易记录表

--库存表的记录为:

insert into Stock values('ADVW',10)
insert into Stock values('BYA',5)



--增加三条交易记录,

insert into Trade values('ADVW',5)
insert into Trade values('BYA',-5)
insert into Trade values('NWT',3)


查询两表的内容


select * from Stock
select * from Trade

Symbol     Qty
---------- -----------
ADVW 10
BYA 5

(2 行受影响)

Symbol Delta
---------- -----------
ADVW 5
BYA -5
NWT 3

(3 行受影响)

 

在交易的时候就应该会影响到库存,这时候就用了merge 。等下我们还要用传统方法来处理然后对比下

 


 

merge Stock 
using Trade
on Stock.Symbol=Trade.Symbol
when matched and (Stock.Qty+Trade.Delta=0) then --就是如果交易和库存一样的话就删除这条记录
DELETE
when matched then
UPDATE SET Stock.Qty+=Trade.Delta --有交易也在库存里有 就减去交易
when not matched then
insert values(Trade.Symbol,Trade.Delta); --有交易没有库存的就加到库存里

select * from Stock
select * from Trade

Symbol Qty
---------- -----------
ADVW 15
NWT 3

(2 行受影响)

Symbol Delta
---------- -----------
ADVW 5
BYA -5
NWT 3

(3 行受影响)


 

使用Merge进行表复制

  生成两个表,在存储过程执行一次复制一次

 

create table Original(PK int primary key ,Fname varchar(10),Number int)
create table Replica(PK int primary key ,Fname varchar(10),Number int)



create procedure uspSyncReplica
as
Merge Replica r using Original o on o.PK=r.PK
WHEN MATCHED AND (o.Fname!=r.Fname or o.Number!=r.Number) then
update set r.Fname=o.Fname , r.Number=o.Number
when not matched then
insert values(o.PK,o.Fname,o.Number)
when not matched by source then
delete;

INSERT INTO Original VALUES(1,'Stephen',10)
INSERT INTO Original VALUES(2,'Jack',20)
INSERT INTO Original VALUES(3,'BEILL',30)
select *from Original
select *from Replica
/*
PK Fname Number
----------- ---------- -----------
1 Stephen 10
2 Jack 20
3 BEILL 30

(3 行受影响)

PK Fname Number
----------- ---------- -----------

(0 行受影响)
*/
EXECUTE uspSyncReplica
/*
(3 行受影响)
*/

select *from Original
select *from Replica
/*
PK Fname Number
----------- ---------- -----------
1 Stephen 10
2 Jack 20
3 BEILL 30

(3 行受影响)

PK Fname Number
----------- ---------- -----------
1 Stephen 10
2 Jack 20
3 BEILL 30

(3 行受影响)
*/


 

在上面的存储过程执行一次复制一次    使用$action虚拟列查询MERGE输出如下

  
alter procedure uspSyncReplica
as
Merge Replica r using Original o on o.PK=r.PK
WHEN MATCHED AND (o.Fname!=r.Fname or o.Number!=r.Number) then
update set r.Fname=o.Fname , r.Number=o.Number
when not matched then
insert values(o.PK,o.Fname,o.Number)
when not matched by source then
delete
output $action ,inserted.*,deleted.*;

INSERT INTO Original VALUES(1,'Stephen',10)
INSERT INTO Original VALUES(2,'Jack',20)
INSERT INTO Original VALUES(3,'BEILL',30)
select *from Original
select *from Replica


 

EXECUTE uspSyncReplica 

$action    PK          Fname      Number      PK          Fname      Number
---------- ----------- ---------- ----------- ----------- ---------- -----------
INSERT     1           Stephen    10          NULL        NULL       NULL
INSERT     2           Jack       20          NULL        NULL       NULL
INSERT     3           BEILL      30          NULL        NULL       NULL

(3 行受影响)



 

查询复制后的表

PK          Fname      Number
----------- ---------- -----------
1 Stephen 10
2 Jack 20
3 BEILL 30

(3 行受影响)

PK Fname Number
----------- ---------- -----------
1 Stephen 10
2 Jack 20
3 BEILL 30

(3 行受影响)


 

如:有一个表 customer, 现在要用一个procedure过程,插入数据,如果表customer中有条数据就更新,没有就新增。

 

if OBJECT_ID('customer')is not null
drop table customer
go
create table customer(
Customerid int primary key,
Firstname varchar(30),
Lastname varchar(30),
Balance decimal
)

create procedure usUpsertCustomer
(
@Customerid int ,
@Firstname varchar(30),
@Lastname varchar(30),
@Balance decimal
)as
merge customer c
using
(select @Customerid as Customerid ,@Firstname as Firstname ,@Lastname as Lastname ,@Balance as Balance)p
on c.Customerid=p.Customerid
when not matched then
insert values(p.Customerid,p.Firstname,p.Lastname,p.Balance)
when matched then
update set c.Customerid=p.Customerid,c.Firstname=p.Firstname,c.Balance=p.Balance
output $action,deleted.*,inserted.*;


execute usUpsertCustomer 1,'Stephen','Zhou',10
/*
$action Customerid Firstname Lastname Balance Customerid Firstname Lastname Balance
---------- ----------- ------------------------------ ------------------------------ --------------------------------------- ----------- ------------------------------ ------------------------------ ---------------------------------------
UPDATE 1 Stephen Zhou 10 1 Stephen Zhou 10

(1 行受影响)
*/
select * from customer
/*
Customerid Firstname Lastname Balance
----------- ------------------------------ ------------------------------ ---------------------------------------
1 Stephen Zhou 10

(1 行受影响)

*/
execute usUpsertCustomer 1,'Stephen','Jack',20
/*
$action Customerid Firstname Lastname Balance Customerid Firstname Lastname Balance
---------- ----------- ------------------------------ ------------------------------ --------------------------------------- ----------- ------------------------------ ------------------------------ ---------------------------------------
UPDATE 1 Stephen Zhou 10 1 Stephen Zhou 20

(1 行受影响)
*/

select * from customer
/*
Customerid Firstname Lastname Balance
----------- ------------------------------ ------------------------------ ---------------------------------------
1 Stephen Zhou 20

(1 行受影响)
*/


 

 

以上基本上介绍了下merge的使用 现在把这个联合 output...into...

 

 

create table book (
isbn varchar(20) primary key ,
price decimal,
shelf int
)
create table weeklychange(
isbn varchar(20) primary key,
price decimal,
shelf int
)
create table bookhistory(
[Action] nvarchar(10),
newISBN varchar(20),
newprice decimal,
newshelf int,
oldisbn varchar(20),
oldprice decimal,
oldshelf int,
archivedat datetime2
)
create procedure uspupdatebooks as
begin
merge book b using weeklychange w on b.isbn=w.isbn
when not matched then
insert values (w.isbn,w.price,w.shelf)
when matched and (w.isbn!=b.isbn or w.price!=b.price or w.shelf!=b.shelf) then
update set b.isbn=w.isbn , b.price=w.price,b.shelf=w.shelf
output $action,inserted.*,deleted.*,sysdatetime() into bookhistory;
end


insert into weeklychange values('SQL程序设计',89,1)

select * from book
select * from weeklychange
select * from bookhistory
/*
isbn price shelf
-------------------- --------------------------------------- -----------

(0 行受影响)

isbn price shelf
-------------------- --------------------------------------- -----------
SQL程序设计 89 1

(1 行受影响)

Action newISBN newprice newshelf oldisbn oldprice oldshelf archivedat
---------- -------------------- --------------------------------------- ----------- -------------------- --------------------------------------- ----------- ----------------------

(0 行受影响)
*/

execute uspupdatebooks
select * from book
select * from weeklychange
select * from bookhistory

/*
isbn price shelf
-------------------- --------------------------------------- -----------
SQL程序设计 89 1

(1 行受影响)

isbn price shelf
-------------------- --------------------------------------- -----------
SQL程序设计 89 1

(1 行受影响)

Action newISBN newprice newshelf oldisbn oldprice oldshelf archivedat
---------- -------------------- --------------------------------------- ----------- -------------------- --------------------------------------- ----------- ----------------------
INSERT SQL程序设计 89 1 NULL NULL NULL 2012-12-05 14:19:12.29

(1 行受影响)

*/


 

 

 

 

 

 

 

 *作者:Stephenzhou(阿蒙)     
 *日期: 2012.12.5
 *Mail:szstephenzhou@163.com     
 *另外:转载请著名出处。
 *博客地址:http://blog.csdn.net/szstephenzhou