oracle循环执行merge,How To Use Oracle MERGE Clause?

MERGE操作可以用一条语句实现UPDATE和INSERT,而且它比传统的关联子查询可能效率更好,避免了FILTER操作,可以走HASH JOIN操作,适合大批量关联更新,下面就来聊聊MERGE语句:MERGE操作的语法如下:

MERGE INTOtable_name AS table_alias

USING(table|view|sub_query) AS alias //单表或视图不需要括号,内联视图要括号

ON(join condition)//必须要有括号

WHEN MATCHED THEN

UPDATE SET

col1 =

col_val1,

col2 =

col2_val--9i不可以有where条件,10g可以

WHEN NOT MATCHED THEN

INSERT(column_list)—多个列以逗号分割//可以不指定列

VALUES(column_values);--9i不可以有where条件,10g可以

作用:将源数据(来源于实际的表,视图,子查询)更新或插入到指定的表中(必须实际存在),依赖于on条件,好处是避免了多个insert和update操作。Merge是一个目标性明确的操作符,不允许在一个merge语句中对相同的行insert或update操作。这个语法仅需要一次全表扫描就完成了全部工作,执行效率要高于INSERT+UPDATE。在update关联更新的时候,如果可以用merge搞定,特别是10g可以允许单个merge

update/insert,比一般的关联更新减少表的扫描提高效率。例子如下:

droptablet;

CREATETABLETASSELECTROWNUMID, A.*FROMDBA_OBJECTS A;

droptablet1;

CREATETABLET1AS

SELECTROWNUMID,

OWNER, TABLE_NAME,CAST('TABLE'ASVARCHAR2(100)) OBJECT_TYPE

FROMDBA_TABLES;

select*fromdba_objects;

select*fromdba_tables;

MERGEINTOT1USINGT

ON(T.OWNER = T1.OWNERANDT.OBJECT_NAME = T1.TABLE_NAMEANDT.OBJECT_TYPE = T1.OBJECT_TYPE)

WHENMATCHEDTHENUPDATESETT1.ID= T.ID

WHENNOTMATCHEDTHENINSERTVALUES(T.ID, T.OWNER, T.OBJECT_NAME, T.OBJECT_TYPE);--insert后面不写表示插入全部列

--这个是对update的要求,对insert没有这个要求,可以与update inline view方法对比,nline view方法是要求有preserved key的,这个不需要,但是对t1列的每行必须唯一找到t的一行才行

MERGEINTOT1USINGT

ON(T.OWNER = T1.OWNERANDT.OBJECT_NAME = T1.TABLE_NAME)

WHENMATCHEDTHENUPDATESETT1.ID= T.ID

WHENNOTMATCHEDTHENINSERTVALUES(T.ID, T.OWNER, T.OBJECT_NAME, T.OBJECT_TYPE);--常见错误,连接条件不能获得稳定的行,可以使用下面的用子查询

--只能一行被更新行找到一行稳定的数据源行,可以想办法做这个动作

MERGEINTOT1

USING(SELECTOWNER, OBJECT_NAME,MAX(ID)IDFROMTGROUPBYOWNER, OBJECT_NAME) T

ON(T.OWNER = T1.OWNERANDT.OBJECT_NAME = T1.TABLE_NAME)

WHENMATCHEDTHENUPDATESETT1.ID= T.ID

WHENNOTMATCHEDTHENINSERTVALUES(T.ID,

T.OWNER, T.OBJECT_NAME);

关于不能获取稳定更新行的错误探讨,其他update同样有这样的问题。。。。。。。

droptablea;

droptableb;

createtablea(idnumber,namevarchar2(10));

createtableb(idnumber,namevarchar2(10),extvarchar2(10));

insertintoavalues(1,'x');

insertintoavalues(2,'y');

insertintobvalues(1,'y','x');

insertintobvalues(1,'z','x');

insertintobvalues(2,'m','x');

INSERTINTObVALUES(3,'n','x');

commit;

SELECT*FROMa;

--1.报错,因为按条件每个a对用多个b的行,主要无法确定用哪行更新a

mergeintoausingb

on(a.id=b.idandb.ext='x')

whenmatchedthen

updateseta.name=b.name;

mergeintoausingb

on(a.id=b.idandb.ext='x')

whenmatchedthen

updateseta.name=b.name

ORA-30926:无法在源表中获得一组稳定的行

--加rownum可以更新

mergeintoausingb

on(a.id=b.idandb.ext='x'ANDROWNUM=1)

whenmatchedthen

updateseta.name=b.NAME;

--但是加了rownum,则有insert则会报错,因为有满足的会跑到insert里

mergeintoausingb

on(a.id=b.idandb.ext='x'ANDROWNUM=1)

whenmatchedthen

updateseta.name=b.NAME

WHENNOTMATCHEDTHEN

INSERT(ID,NAME)VALUES(b.ID,b.NAME);

--上面的直接insert不报错,因为这里的insert能取到稳定的不满足行

mergeintoausingb

on(a.id=b.idandb.ext='x')

WHENNOTMATCHEDTHEN

INSERT(ID,NAME)VALUES(b.ID,b.NAME);

--OK,对这种情况,则可以使用两次merge,一次单独的update+rownum,一次单独的insert

--合二唯一方案,获取取稳定的更新行,想办法拼凑,分组,排名,rowid等

mergeintoausing(SELECTid,name,extFROM(

SELECTID,NAME,ext,row_number()over(PARTITIONBYIDORDERBYROWID)rnFROMb

WHEREext='x'

)WHERErn=1)b

on(a.id=b.ID)

whenmatchedthen

updateseta.name=b.NAME

WHENNOTMATCHEDTHEN

INSERT(ID,NAME)VALUES(b.ID,b.NAME);

SELECTID,

OWNER, OBJECT_NAME, OBJECT_TYPEFROMT

MINUS

SELECT*FROMT1;

droptablesubs;

createtablesubs(msidnumber(9),

ms_typechar(1),

areacodenumber(3)

);

droptableacct;

createtableacct(msidnumber(9),

bill_monthnumber(6),

areacodenumber(3),

feenumber(8,2)default0.00);

insertintosubsvalues(905310001,0,531);

insertintosubsvalues(905320001,1,532);

insertintosubsvalues(905330001,2,533);

commit;

mergeintoacct a--操作的表

usingsubs bon(a.msid=b.msid)--使用原始数据来源的表,并且制定条件,条件必须有括号

whenmatchedthen

updateseta.areacode=b.areacode--当匹配的时候,执行update操作,和直接update的语法不一样,不需要制定表名

whennotmatchedthen--当不匹配的时候,执行insert操作,也不需要制定表名,若指定字段插入,则在insert后用括号标明,不指定是全部插入

insert(msid,bill_month,areacode)values(b.msid,'200702',b.areacode);

另外,MERGE语句的UPDATE不能修改用于连接的列,否则会报错

select*fromacct;

select*fromsubs;

--10g新特性,单个操作

mergeintoacct a

usingsubs bon(a.msid=b.msid)

whennotmatchedthen--只有单个not matched的时候,只做插入,不做更新,只有单个matched的时候,只做更新操作

insert(a.msid,a.bill_month,a.areacode)values(b.msid,'200702',b.areacode);

updateacctsetareacode=800wheremsid=905320001;

deletefromacctwhereareacode=533orareacode=531;

insertintoacctvalues(905320001,'200702',800,0.00);

--删除重复行

deletefromsubs bwhereb.rowid

selectmax(a.rowid)fromsubs awherea.msid=b.msidanda.ms_type=b.ms_typeanda.areacode=b.areacode);

--10g新特性,merge操作之后,只有匹配的update操作才可以,用delete where子句删除目标表中满足条件的行。要注意,必须是在匹配的前提条件下,先更新原始表后,删除删除满足条件的行,也就是对更新的行调用删除条件删除,还有单个insert/update功能。

mergeintoacct a

usingsubs bon(a.msid=b.msid)

whenMATCHEDthen

updateseta.areacode=b.areacode

deletewhere(b.ms_type!=0)

whenNOTMATCHEDthen

insert(msid,bill_month,areacode)

values(b.msid,'200702',b.areacode)

whereb.ms_type=0;

--10g新特性,满足条件的插入和更新

mergeintoacct a

usingsubs bon(a.msid=b.msid)

whenMATCHEDthen

updateseta.areacode=b.areacode

whereb.ms_type=0

whenNOTMATCHEDthen

insert(msid,bill_month,areacode)

values(b.msid,'200702',b.areacode)

whereb.ms_type=0;

select*fromsubswherems_type=0;

(10g可以条件插入和条件更新

10g的update能加delete where)

droptablet1;

droptablet2;

createtablet1(idnumber,namevarchar2(10));

createtablet2(idnumber,namevarchar2(10));

insertintot1values(1,'a');

insertintot1values(2,'b');

insertintot1values(3,'c');

insertintot1values(5,'a');

insertintot2values(1,'x');

insertintot2values(2,'y');

insertintot2values(4,'z');

insertintot2values(5,'a');

commit;

---对t2中的id=1和5的更新完后,name变为a,然后调用删除条件

--去掉update的delete会报错的,delete必须在update后,是在匹配的前提下发生的,是update执行之后,按条件删除目标表t2中--的数据

mergeintot2

usingt1on(t1.id=t2.id)

whenMATCHEDthen

updatesett2.name=t1.name

deletewhere(t2.name='a')

whenNOTMATCHEDthen

insert

values(t1.id,t1.name);

--update delete中的delete条件可以是t1,t2中的任意列,因为按合并的删除

现在请问,如果在merge中使用delete的句子,那么删除的字段是否必须是条件判断中的出现的字段?---------------不需要,因为是按匹配的结果先update之后,这时候oracle是知道源表被更新后的数据和数据库的匹配数据的,所以update delete条件可以是源表更新后的结果和数据源的任意列ps:注意是更新后的

mergeintot2

usingt1on(t1.id=t2.id)

whenMATCHEDthen

updatesett2.name=t1.name

deletewhere(t1.name='a')

whenNOTMATCHEDthen

insert

values(t1.id,t1.name);

====》

当然是在匹配的前提下,先更新后删除,merge可以简单解释为,假设就一个id匹配条件,update name

if

t1.id=t2.id then

update set t2.name = t1.name;--先更新,后删除

--删除目标表数据

delete t2 where where exists (select 1 from t1

where t1.id=t2.id and t2….=....)//如果是用目标表条件删除,是这样的

or

delete t2 where exists (select 1 from t1 where

t1.id=t2.id and t1….=....) //如果是用数据源删除是这样的

else

insert into t1…

end

if;

--merge可以是多表关联

MERGE INTO SERV s

USING (

SELECT s.serv_id,m.arr_month,f.arr_fee

FROM serv s LEFT JOIN month m ON s.serv_id=m.serv_id

LEFT JOIN fee f ON s.serv_id=f.serv_id

) d

ON (s.serv_id=d.serv_id)

WHEN MATCHED THEN UPDATE SET s.arr_month=d.arr_month,s.arr_fee=d.arr_fee;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值