Oracle“ORA-38104: 無法更新ON子句中引用的列”解決方式 merge (oracle中merge用法) [Oracle] Merge語句

今天在plsql中使用merge into更新字段時遇到了一個問題。

相關代碼如下:

    MERGE INTO TABLE1 A
    USING (SELECT T.ID, T.NEW_CORE_SIZE FROM TABLE2 T) B
    ON (A.ID = B.ID AND A.CORE_SIZE IS NULL)
    WHEN MATCHED THEN
      UPDATE SET A.CORE_SIZE = B.NEW_CORE_SIZE;

這裏請注意,在ON中出現的字段,不可以在WHEN MATCHED THEN中更新,所以無法更新A.CORE_SIZE字段

正確的寫法如下:

    MERGE INTO TABLE1 A
    USING (SELECT T.ID, T.NEW_CORE_SIZE FROM TABLE2 T) B
    ON (A.ID = B.ID)
    WHEN MATCHED THEN
      UPDATE SET A.CORE_SIZE = DECODE(A.CORE_SIZE,null,B.NEW_CORE_SIZE,A.CORE_SIZE);

merge (oracle中merge用法) - chenhonggao - 博客園 (cnblogs.com)

merge (oracle中merge用法)

 

[Oracle] Merge語句

Merge的語法例如以下:

 

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表中。

大家知道,在等價的情況下,一定需要至少兩條語句,一條爲UPDATE,一條爲INSERT,並且語句中必需要與推斷的邏輯,或者寫在過程中,假設是單條語句,就要寫全條件。
寫在UPDATE和INSERT的語句中,顯的比較麻煩並且easy出錯。假設了解MERGE,我們能夠不借助存儲過程,直接用單條SQL便實現了該業務邏輯,且代碼非常簡潔。詳細例如以下:

 

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                           100
5. 必需要在源表中獲得一組穩定的行
---構造數據,請注意這裏多插入一條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列做一個聚合。這樣歸併成單條,也能避免此類錯誤。

如: */ 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須要引起懷疑,不太應該。

oracle-merge into using on用法_張三李四dw的博客-CSDN博客_merge into using on

在sql中看到如下
截圖:
在這裏插入圖片描述

merge into 表1 using 表2 on(.... and ...) 
when matched then ....
上圖大概樣式

那麼表達什麼意思?


以下內容摘自博文:
https://blog.csdn.net/qq_34745941/article/details/81176140?utm_source=copy

1. 適用場景:'有則更新,無則插入'

2. 好處
   (1) 執行 '效率高'
   (2) 語法簡潔

語法:

merge into 目標表 b
using 源表 a
on (b.字段1 = a.字段1 and b.字段n = a.字段n) -- 必須帶 '()'
when matched then -- 整體掃描,匹配時,執行此處
   update 子句
when not matched then -- 整體掃描,不匹配時,執行此處
   insert 子句;

 

 

Oracle中時間日期轉化函數to_date和to_char用法總結_旺旺_123的博客-CSDN博客_to_char函數用法 日期

  在實際的工作中會經常會用到to_char()、to_date()函數來對時間、日期進行處理。

1、to_char()函數的用法

 1.1、將時間日期按照指定的格式輸出,得到的是字符串,而非date類型。

 

 
  1. select sysdate,to_char(sysdate,'yyyy-mm-dd')from dual;
  2. select sysdate,to_char(sysdate,'yyyy/mm/dd')from dual;
  3. select sysdate,to_char(sysdate,'yyyymmdd')from dual;
  4. select sysdate,to_char(sysdate,'yyyymmdd hh24:mi:ss')from dual;
 

運行的輸出結果爲:

 

 

 
  1. 2017/6/15 17:07:24 2017-06-15
  2. 2017/6/15 17:07:25 2017/06/15
  3. 2017/6/15 17:07:25 20170615
  4. 2017/6/15 17:07:25 20170615 17:07:25
 

 1.2、用to_char()可以得到日期中的年、月、日、時、分

 
  1. select sysdate,to_char(sysdate,'yyyy')from dual;
  2. select sysdate,to_char(sysdate,'mm')from dual;
  3. select sysdate,to_char(sysdate,'hh24')from dual;
  4. select sysdate,to_char(sysdate,'mi')from dual;
 

運行的輸出結果爲:

 

 

 
  1. 2017/6/15 17:09:14 2017
  2. 2017/6/15 17:09:14 06
  3. 2017/6/15 17:09:14 17
  4. 2017/6/15 17:09:14 09
 

 

注:to_char()得到的是字符串,要查詢具體單日、時、分要特別注意。 

 

 
  1. select accept_time,to_char(accept_time,'mi') from TMP_WW_0615_GYTS_S2
  2. where to_char(accept_time,'mi')='06' ;
  3. select accept_time,to_char(accept_time,'mi') from TMP_WW_0615_GYTS_S2
  4. where to_char(accept_time,'mi')='6' ;
 

 運行輸出結果爲:

 

 

 
  1. 2017/6/8 21:06:59 06
  2. null
 

 

2、to_date()函數的用法

 2.1、將字符串轉換爲具體指定的時間日期格式

 

 
  1. select sysdate,to_date('20170615','yyyymmdd')from dual;
  2. select sysdate,to_date('20170615','yyyy-mm-dd')from dual;
  3. select sysdate,to_date('20170615','yyyy/mm/dd')from dual;
  4. select sysdate,to_date('20170615','yyyy-mm-dd hh24:mi:ss')from dual;
 

 運行輸出結果爲:

 

 

 
  1. 2017/6/15 17:20:27 2017/6/15
  2. 2017/6/15 17:20:27 2017/6/15
  3. 2017/6/15 17:20:27 2017/6/15
  4. 2017/6/15 17:20:27 2017/6/15
 

 

注:to_date()得到的日期格式是和系統的日期格式保持一致;

      得到的時間爲當天的 00 :00:00。

2.2、可以直接使用date'yyyy-mm-dd'

 

 select date'2017-5-1',to_date('20170615','yyyymmdd')from dual; 

 

 運行輸出結果爲:

 

 2017/5/1	2017/6/15

注:date'2017/5/1' 會提示格式不對。

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