Merge的語法例如如下:html
MERGE [hint] INTO [schema .] table [t_alias] USING [schema .] { table | view | subquery } [t_alias] ON ( condition ) WHEN MATCHED THEN merge_update_clause WHEN NOT MATCHED THEN merge_insert_clause;MERGE是什麼,怎樣使用呢?讓咱們先看一個簡單的需求:
需求是,從T1表更新數據到T2表中。假設T2表的NAME 在T1表中已存在,就將MONEY累加,假設不存在。將T1表的記錄插入到T2表中。sql
你們知道,在等價的狀況下,必定須要至少兩條語句,一條爲UPDATE,一條爲INSERT,而且語句中必須要與推斷的邏輯,或者寫在過程當中,假設是單條語句,就要寫全條件。
寫在UPDATE和INSERT的語句中,顯的比較麻煩而且easy出錯。假設了解MERGE,咱們可以不借助存儲過程,直接用單條SQL便實現了該業務邏輯,且代碼很是簡潔。詳細例如如下:oracle
MERGE INTO T2 USING T1 ON (T1.NAME=T2.NAME) WHEN MATCHED THEN UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY WHEN NOT MATCHED THEN INSERT VALUES (T1.NAME,T1.MONEY);
Merge的四大靈活之處
上面講了Merge的語法和基本使用方法,其實Merge可以很靈活。
1.UPDATE和INSERT動做可僅僅出現其一(9I必須同一時候出現。)
--咱們可選擇只UPDATE目標表 MERGE INTO T2 USING T1 ON (T1.NAME=T2.NAME) WHEN MATCHED THEN UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY; --也可選擇只INSERT目標表而不作不論什麼UPDATE動做 MERGE INTO T2 USING T1 ON (T1.NAME=T2.NAME) WHEN NOT MATCHED THEN INSERT VALUES (T1.NAME,T1.MONEY);2.可對MERGE語句加條件
MERGE INTO T2 USING T1 ON (T1.NAME=T2.NAME) WHEN MATCHED THEN UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY WHERE T1.NAME='A';3.可用DELETE子句清除行
/* 在這樣的狀況下,首先是要先知足T1.NAME=T2.NAME的記錄,假設T2.NAME=’A’並不知足T1.NAME=T2.NAME過濾出的記錄集, 那這個DELETE是不會生效的。在知足的條件下,可以刪除目標表的記錄。 */ MERGE INTO T2 USING T1 ON (T1.NAME=T2.NAME) WHEN MATCHED THEN UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY DELETE WHERE (T2.NAME = 'A');4.可採用無條件方式Insert
/* 方法很是easy,在語法ONkeyword處寫上恆不等條件(如1=2)後,MATCHED語句的INSERT就變爲無條件INSERT了,詳細例如如下 */ MERGE INTO T2 USING T1 ON (1=2) WHEN NOT MATCHED THEN INSERT VALUES (T1.NAME,T1.MONEY);
Merge的誤區
1. 不能更新ON子句引用的列MERGE INTO T2 USING T1 ON (T1.NAME=T2.NAME) WHEN MATCHED THEN UPDATE SET T2.NAME=T1.NAME; ORA-38104: 沒法更新 ON 子句中引用的列: "T2"."NAME"2. DELETE子句的WHERE順序必須最後
MERGE INTO T2 USING T1 ON (T1.NAME=T2.NAME) WHEN MATCHED THEN UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY DELETE WHERE (T2.NAME = 'A') WHERE T1.NAME='A'; ORA-00933: SQL 命令未正確結束3.DELETE 子句僅僅可以刪除目標表。而沒法刪除源表
/* 這裏需要引發注意,無論DELETE WHERE (T2.NAME = 'A' )這個寫法的T2是否改寫爲T1。效果都同樣,都是對目標表進行刪除。 */ SELECT * FROM T1; NAME MONEY -------------------- ---------- A 10 B 20 SELECT * FROM T2; NAME MONEY -------------------- ---------- A 30 C 20 MERGE INTO T2 USING T1 ON (T1.NAME=T2.NAME) WHEN MATCHED THEN UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY DELETE WHERE (T2.NAME = 'A' ); SELECT * FROM T1; NAME MONEY -------------------- ---------- A 10 B 20 SELECT * FROM T2; NAME MONEY -------------------- ---------- C 20
4.更新同一張表的數據,需操心USING的空值
SELECT * FROM T2; NAME MONEY -------------------- ---------- A 30 C 20 /* 需求爲對T2表進行自我更新。假設在T2表中發現NAME=D的記錄,就將該記錄的MONEY字段更新爲100,假設NAME=D的記錄不存在, 則本身主動添加。NAME=D並且MONEY=100的記錄。依據語法完畢例如如下代碼: */ MERGE INTO T2 USING (select * from t2 where NAME='D') T ON (T.NAME=T2.NAME) WHEN MATCHED THEN UPDATE SET T2.MONEY=100 WHEN NOT MATCHED THEN INSERT VALUES ('D',200); --但是查詢發現。原本T表應該因爲NAME=D不存在而要添加記錄。但是實際卻根本無變化。 SQL> SELECT * FROM T2; NAME MONEY ------------------------------------------------------- A 30 C 20 /* 原來是因爲此時select * from t2 where NAME='D'爲NULL,因此出現了沒法插入的狀況。 咱們可以利用COUNT(*)的值不會爲空的特色來等價改造。詳細例如如下: */ MERGE INTO T2 USING (select COUNT(*) CNT from t2 where NAME='D') T ON (T.CNT<>0) WHEN MATCHED THEN UPDATE SET T2.MONEY=100 WHEN NOT MATCHED THEN INSERT VALUES ('D',100); SQL> SELECT * FROM T2; NAME MONEY ------------------------------- A 30 C 20 D 1005. 必須要在源表中得到一組穩定的行
---構造數據,請注意這裏多插入一條A記錄,就產生了ORA-30926錯誤 INSERT INTO T1 VALUES ('A',30); COMMIT; ---此時繼續運行例如如下 MERGE INTO T2 USING T1 ON (T1.NAME=T2.NAME) WHEN MATCHED THEN UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY; ORA-30926: 沒法在源表中得到一組穩定的行 /* oracle中的merge語句應該保證on中的條件的惟一性,T1.NAME=T2.NAME的時候。T1表記錄相應到了T2表的兩條記錄,因此就出錯了。
解決方法很是easy。比方咱們可以對T1表和T2表的關聯字段建主還鍵,這樣基本上就不可能出現這種問題,而且通常而言,MERGE語句的關聯字段互相有主鍵。 MERGE的效率將比較高!或者是將T1表的ID列作一個聚合。這樣歸併成單條,也能避免此類錯誤。post
如: */ MERGE INTO T2 USING (select NAME,SUM(MONEY) AS MONEY FROM T1 GROUP BY NAME)T1 ON (T1.NAME=T2.NAME) WHEN MATCHED THEN UPDATE SET T2.MONEY=T1.MONEY+T2.MONEY; --正常狀況下,通常出現反覆的NAME需要引發懷疑,不太應該。url