ORA-38104 - Что такое обходной путь обновления столбца в предложении ON в MERGE? - PullRequest
0 голосов
/ 17 ноября 2018

У меня есть table FOO с некоторыми значениями идентификатора в col N_RA_ID для MANUAL% значений в col V_CUST_NUMBER и некоторыми совпадающими значениями в col N_RA_ID для неручных значений в col V_CUST_NUMBER. Вот пример данных -

TABLE FOO

Я хочу самостоятельно присоединиться к col N_RA_ID, и там, где есть точное совпадение, я хочу update N_RA_ID до null WHERE V_CUST_NUMBER LIKE 'MANUAL%'

поэтому вывод должен выглядеть следующим образом -

Output

Я попытался использовать слияние, но получил ORA-38104. Кто-нибудь может помочь, пожалуйста?

MERGE INTO FOO X 
USING  (
SELECT T1.V_CUST_NUMBER AS MAN_CUST,T1.N_RA_ID, T2.V_CUST_NUMBER
FROM FOO T1
JOIN FOO T2
ON T1.N_RA_ID = T2.N_RA_ID
AND UPPER(T1.V_CUST_NUMBER) NOT LIKE 'MANUAL%'

) Z
ON (X.N_RA_ID = Z.N_RA_ID)
WHEN MATCHED THEN UPDATE
SET X.N_RA_ID = null
WHERE UPPER(X.V_CUST_NUMBER) LIKE 'MANUAL%'


SQL Error: ORA-38104: Columns referenced in the ON Clause cannot be updated: "X"."N_RA_ID"
38104. 00000 -  "Columns referenced in the ON Clause cannot be updated: %s"
*Cause:    LHS of UPDATE SET contains the columns referenced in the ON Clause
*Action:

Ответы [ 3 ]

0 голосов
/ 17 ноября 2018

Обычный обходной путь - выбрать T2.ROWID as RID в предложении USING, а затем вместо совпадения на N_RA_ID вы соответствуете ON X.ROWID = Z.RID.

Вот так:

MERGE INTO FOO X 
USING  (
SELECT T2.ROWID AS RID,           -- ADD THIS HERE
       T1.V_CUST_NUMBER AS MAN_CUST,T1.N_RA_ID, T2.V_CUST_NUMBER
FROM FOO T1
JOIN FOO T2
ON T1.N_RA_ID = T2.N_RA_ID
AND UPPER(T1.V_CUST_NUMBER) NOT LIKE 'MANUAL%'   
) Z
ON (X.ROWID = Z.RID)              -- CHANGE THE "ON" CLAUSE LIKE THIS
WHEN MATCHED THEN UPDATE
SET X.N_RA_ID = null
WHERE UPPER(X.V_CUST_NUMBER) LIKE 'MANUAL%'
0 голосов
/ 02 января 2019

Начиная с Oracle 18c, существуют некоторые обходные пути, которые можно применять к таким MERGE операторам , которые превосходят парсер, который проверяет предварительные условия ORA-38104 .Например, вы можете использовать выражения значения строки с дополнительным фиктивным сравнением столбцов:

MERGE INTO FOO X 
USING  (
  SELECT T1.V_CUST_NUMBER AS MAN_CUST,T1.N_RA_ID, T2.V_CUST_NUMBER
  FROM FOO T1
  JOIN FOO T2
  ON T1.N_RA_ID = T2.N_RA_ID
  AND UPPER(T1.V_CUST_NUMBER) NOT LIKE 'MANUAL%'
) Z
ON ((X.N_RA_ID, 'dummy') = ((Z.N_RA_ID, 'dummy')))
WHEN MATCHED THEN UPDATE
SET X.N_RA_ID = null
WHERE UPPER(X.V_CUST_NUMBER) LIKE 'MANUAL%'
0 голосов
/ 17 ноября 2018

Вы можете выполнить простое обновление с проверкой exists ():

update foo f1
set n_ra_id = null
where v_cust_number like 'MANUAL%'
and exists (
  select *
  from foo f2
  where f2.n_ra_id = f1.n_ra_id
  and v_cust_number not like 'MANUAL%'
);

Основное обновление сначала фильтрует все строки, начинающиеся с 'MANUAL', а подзапрос внутри exists() ищет любойстрока в таблице с тем же идентификатором, но не начинающаяся с «РУЧНАЯ».Если такой строки, не относящейся к ручному управлению, не существует, тогда это условие ложно, а строка вручную остается без изменений;если есть совпадение, то строка обновляется.

Демо:

select * from foo;

V_CUST_NU    N_RA_ID
--------- ----------
MANUAL033      17024
MANUAL034     589469
MANUAL035     589470
MANUAL036     589478
BHASAD        589478

update foo f1
set n_ra_id = null
where v_cust_number like 'MANUAL%'
and exists (
  select *
  from foo f2
  where f2.n_ra_id = f1.n_ra_id
  and v_cust_number not like 'MANUAL%'
);

1 row updated.

select * from foo;

V_CUST_NU    N_RA_ID
--------- ----------
MANUAL033      17024
MANUAL034     589469
MANUAL035     589470
MANUAL036           
BHASAD        589478
...