ORA-38104-在MERGE中更新ON子句中的列的解决方法是什么?

时间:2018-11-16 21:52:15

标签: sql oracle sql-update oracle12c

我有table FOO,其中col N_RA_IDMANUAL%的值在col V_CUST_NUMBER中有一些ID值,对于col N_RA_ID中的非手动值,在col V_CUST_NUMBER中有一些匹配值{1}}。这是示例数据-

here

我想在col N_RA_ID上自行加入,只要有完全匹配的地方,我就想update N_RA_IDnull WHERE V_CUST_NUMBER LIKE 'MANUAL%'

因此输出应类似于-

TABLE FOO

我尝试使用合并,但得到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 :(得分:2)

您可以使用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()内的子查询在表中查找具有相同ID但不以'MANUAL'开头的任何行。如果没有这样的非手动行,则该子句为false,手动行保持不变;如果存在匹配项,则更新该行。

演示:

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

答案 1 :(得分:2)

通常的解决方法是在OUTGOING_TYPE子句中选择T2.ROWID as RID,然后匹配USING,而不是在N_RA_ID上进行匹配。

像这样:

ON X.ROWID = Z.RID

答案 2 :(得分:0)

从Oracle 18c开始,存在一些变通办法可以应用于此类MERGE语句which outsmart the parser who checks for ORA-38104 preconditions。例如,您可以将行值表达式与其他虚拟列比较一起使用:

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%'