Oracle MERGE語句

目的

使用MERGE語句從一個或多個數據源中選擇數據插入到一個表或視圖中。你可以指定條件,以確定是否更新或插入目標表或視圖

MERGE語句是一種方便結合多個操作的方式,它可以讓你避免多個INSERTUPDATE和DELETEDML語句

MERGE是一種確定性的語句,在同一個MERGE語句中不能多次更新目標表的同一行。

前提

       你必須有目標表的INSERT和UPDATE對象權限和源表的SELECT對象權限。要指定merge_update_clause的DELETE從句,也必須要有目標表的DELETE對象權限。

 

語法

MERGE [ hint ]
   INTO [ schema. ] { table | view } [ t_alias ]
   USING { [ schema. ] { table | view }
         | subquery 
         } [ t_alias ]
   ON ( condition )
   [ merge_update_clause ]
   [ merge_insert_clause ]
   [ error_logging_clause ] ;

注意:雖然這個SQL語句有UPDATE、INSERT和LOGGING從句,但是只能有一個分號(;)。

  • merge_update_clause從句
WHEN MATCHED THEN
UPDATE SET column = { expr | DEFAULT }
           [, column = { expr | DEFAULT } ]...
[ where_clause ]
[ DELETE where_clause ]
  • merge_inser_clause
WHEN NOT MATCHED THEN
INSERT [ (column [, column ]...) ]
VALUES ({ expr [, expr ]... | DEFAULT })
[ where_clause ]
  • error_logging_clause
LOG ERRORS 
  [ INTO [schema.] table ]
  [ (simple_expression) ]
  [ REJECT LIMIT { integer | UNLIMITED } ]

語義

INTO 子句

使用into子句指定要插入和更新的目標表或視圖。

USING 子句

使用using子句指定插入和更新的數據源。數據源可以一張表、視圖或是子查詢。

ON子句

使用on子句指定merge操作條件是插入或更新。對於目標表搜索條件爲真時,Oracle數據庫從源表獲取數據更新到目標表的相應行。如果條件不成立的任意行,則數據庫插入基於來源表相應的行到目標表。

merge_update_clause

 merge_update_clause指定目標表的新列值。如果ON子句的條件爲真,Oracle執行更新。如果update子句被執行,那麼所有目標表上定義的更新觸發器都被激活。

如果你想數據庫只有指定條件爲真時才執行更新操作,則需要指定 where_clause。條件可以參考數據源或目標表。如果條件爲假,則合併表時數據庫跳過更新操作。

指定 DELETE where_clause刪除表中正在填充或更新的數據。該從句隻影響目標表中被合併操作更新的行。DELETE WHERE條件求被UPDATE SET ... WHERE計算後的更新值,而不是原始值。如果目標表的行滿足DELETE條件,但不包含在ON子句中所定義的條件,該行是不被刪除的。定義在目標表上的刪除觸發器在刪除每一行後都會被觸發。

merge_insert_clause

如果ON子句的條件爲假, merge_insert_clause 指定值插入到目標表的列上。如果INSERT子句被執行,那麼定義在目標表上的所有插入觸發器被激活。如果省略了INSERT關鍵字後列的列表,則目標的列數必須與VALUES子句中值的列數匹配。

爲了將來源表的所有行都插入目標表,可以在ON子句中使用常量過濾條件。一個常量過濾條件的例子是ON(1=0)。Oracle承認這樣一個常量條件,並無條件插入源表所有行到目標表。這種方法是不同於省略 merge_update_clause,在這樣情況下,數據庫仍然執行關聯。使用常量過濾條件,沒有關聯被執行。

如果想要數據執行插入操作僅僅是指定條件爲真時,則需要指定 where_clause 。該條件只能是參考數據源表。Oracle數據庫跳過所有行條件爲假的插入操作。

error_logging_clause

在合併語句中error_logging_clause具有與INSERT語句相同的行爲。

 

Examples

創建員工表emp,部門表depart和獎金錶bonuses。

創建員工表

create  table emp(
employee_id number,
employee_code varchar2(30),
employee_name varchar2(50),
brithdate date,
depart_id number);

insert into emp values (1,'0001','KIT',date'1996-10-18',1);
insert into emp values (2,'0002','張三',date'2013-10-3',1);
insert into emp values (3,'0003','李四',date'2003-11-23',2);
insert into emp values (4,'0004','王五',date'2001-1-06',2);
insert into emp values (5,'0005','小六',date'2011-09-08',3);

創建部門表

create  table depart (
depart_id number,
depart_code varchar2(30),
depart_name varchar2(50));

insert into depart values  (1,'10','市場部');
insert into depart values  (2,'20','研發部');
insert into depart values (3,'30','拓展部');
insert into depart values  (4,'40','後勤部');

創建獎金錶create table bonuses (
employee_id number,
bonuses number not null);

 

創建日誌表
create table logs(
log_id number,
log_message varchar2(200));

1.按照部門的發放獎金,市場部100,研發部200,拓展部200,後勤部80。使用merge語句插入各部門員工的獎金。

merge into bonuses b
using (select e.employee_id, e.employee_name, d.depart_id, d.depart_code
         from emp e, depart d
        where e.depart_id = d.depart_id) a
on (b.employee_id = a.employee_id)
when not matched then
  insert
    (b.employee_id, b.bonuses)
  values
    (a.employee_id,
     decode(a.depart_code, '10', 100, '20', 200, '30', 200, '40', 80));

查詢獎金錶

SQL> select * from bonuses;
 
EMPLOYEE_ID    BONUSES
----------- ----------
          5        200
          4        200
          3        200
          1        100
          2        100

 

2.市場不所有員工,在原來獎金的基礎上加20%。

merge into bonuses b
using (select e.employee_id, e.employee_name, d.depart_id, d.depart_code
         from emp e, depart d
        where e.depart_id = d.depart_id
          and d.depart_code = '10') a
on (b.employee_id = a.employee_id)
when matched then
  update set b.bonuses = b.bonuses + b.bonuses * 0.2;

查詢獎金錶

SQL> select *from bonuses;
 
EMPLOYEE_ID    BONUSES
----------- ----------
          5        200
          4        200
          3        200
          1        120
          2        120

市場部的員工的獎金有原來的100變成了120。

3.刪除研發部員工張三的獎金,其他員工獎金減少10%。

merge into bonuses b
using (select e.employee_id, e.employee_name, d.depart_id, d.depart_code
         from emp e, depart d
        where e.depart_id = d.depart_id
          and d.depart_code = '20') a
on (b.employee_id = a.employee_id)
when matched then
  update
     set b.bonuses = b.bonuses - b.bonuses * 0.1
  delete where b.employee_id = 3;

 

查詢獎金:

SQL> select *from bonuses;
 
EMPLOYEE_ID    BONUSES
----------- ----------
          5        200
          4        180
          1        120
          2        120

研發部現在只有李四有獎金,由原來的200變爲180.。

 

注意:使用DELETE子句有以下條件限制。

a.刪除記錄比較在目標表中存在。

b.必須滿足On子句的條件。

c.刪除的記錄必須包含update set ...子句中。

 

4.研發部門所有有獎金的員工,獎金加30%,沒有獎金的員工加200.

merge into bonuses b
using (select e.employee_id, e.employee_name, d.depart_id, d.depart_code
         from emp e, depart d
        where e.depart_id = d.depart_id
          and d.depart_code = '20') a
on (b.employee_id = a.employee_id)
when matched then
  update set b.bonuses = b.bonuses + b.bonuses * 0.3
when not matched then
  insert (b.employee_id, b.bonuses) values (a.employee_id, 200);

 

查詢獎金錶

SQL> select *from bonuses;
 
EMPLOYEE_ID    BONUSES
----------- ----------
          5        200
          4        234
          3        200
          1        120
          2        120

研發部張三原來沒有獎金,現在爲200。李四由180變成234.

 

5.創建創建錯誤日誌表

SQL> EXECUTE DBMS_ERRLOG.CREATE_ERROR_LOG('bonuses', 'errlog');
將錯誤日誌表與獎金關聯在一起,這樣在做獎金錶錯誤時。如果發生錯誤,就會將錯誤信息記錄到日誌表。

例如,將拓展部員工的獎金置空。


merge into bonuses b
using (select e.employee_id, e.employee_name, d.depart_id, d.depart_code
         from emp e, depart d
        where e.depart_id = d.depart_id
          and d.depart_code = '30') a
on (b.employee_id = a.employee_id)
when matched then
  update set b.bonuses = null
log errors into errlog('bonuses_error') reject limit 20;

查看獎金錶

SQL> select *from bonuses;
 
EMPLOYEE_ID    BONUSES
----------- ----------
          5        200
          4        234
          3        200
          1        120
          2        120

發現拓展部的員工小劉的獎金還是200,並沒有置空。

查看錯誤日誌表

SQL> select ORA_ERR_NUMBER$,ORA_ERR_MESG$ from errlog;
 
ORA_ERR_NUMBER$ ORA_ERR_MESG$
--------------- --------------------------------------------------------------------------------
           1407 ORA-01407: 無法更新 ("GDSHEC"."BONUSES"."BONUSES") 爲 NULL

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章