Fre*_*Nil 27 sql oracle merge ora-38104
我有一个带删除标志的简单表(记录应该在此列中更新而不是删除):
create table PSEUDODELETETABLE
(
ID NUMBER(8) not null, -- PKEY
NAME VARCHAR2(50) not null,
ISDELETED NUMBER(1) default 0 not null
)
Run Code Online (Sandbox Code Playgroud)
插入新记录时,我必须检查是否已存在与主键匹配但是ISDELETED = 1的记录.在这种情况下,我必须将ISDELETED更改为0并更新其他列.因此我使用以下Merge-Statement:
merge into ET.PSEUDODELETETABLE TARGET
using (select 1 as ID, 'Horst' as NAME from sys.dual) SOURCE
on (TARGET.ISDELETED = 1 and SOURCE.ID = TARGET.ID)
when matched then
update set ISDELETED = 0, NAME = SOURCE.NAME
when not matched then
insert values (SOURCE.ID, SOURCE.NAME, 0);
Run Code Online (Sandbox Code Playgroud)
在Sql-Server上它运行良好,但Oracle说:
ORA-38104: Columns referenced in the ON Clause cannot be updated: TARGET.ISDELETED
Run Code Online (Sandbox Code Playgroud)
如果存在IDELETED = 0的匹配记录,我希望将主键冲突作为例外,这就是为什么我不能将"TARGET.ISDELETED = 1"从on-clause移动到update-statement.
Dav*_*arx 43
与接受的响应相反,实际上有一种方法可以解决这个问题:将违规位移出ON子句并进入update语句的WHERE子句:
merge into ET.PSEUDODELETETABLE TARGET
using (select 1 as ID, 'Horst' as NAME from sys.dual) SOURCE
on (SOURCE.ID = TARGET.ID)
when matched then
update
set ISDELETED = 0,
NAME = SOURCE.NAME
where TARGET.ISDELETED = 1 -- Magic!
when not matched then
insert
values (SOURCE.ID, SOURCE.NAME, 0);
Run Code Online (Sandbox Code Playgroud)
将列放入某种表达式中并重命名似乎可行。在下面的示例中,ISDELETED_
和ISDELETED
实际上是同一件事:
merge into (
select nvl(ISDELETED, ISDELETED) as ISDELETED_, ISDELETED, ID,
from ET.PSEUDODELETETABLE
) TARGET
using (select 1 as ID, 'Horst' as NAME from sys.dual) SOURCE
on (TARGET.ISDELETED_ = 1 and SOURCE.ID = TARGET.ID) -- Use the renamed version here
when matched then
update set ISDELETED = 0, NAME = SOURCE.NAME -- Use the original version here
when not matched then
insert values (SOURCE.ID, SOURCE.NAME, 0);
Run Code Online (Sandbox Code Playgroud)
注意:
这似乎也有效,但绝对似乎不允许任何合理的索引使用(请再次检查您的 Oracle 版本):
merge into ET.PSEUDODELETETABLE TARGET
using (select 1 as ID, 'Horst' as NAME from sys.dual) SOURCE
on ((select TARGET.ISDELETED from dual) = 1 and SOURCE.ID = TARGET.ID)
when matched then
update set ISDELETED = 0, NAME = SOURCE.NAME
when not matched then
insert values (SOURCE.ID, SOURCE.NAME, 0);
Run Code Online (Sandbox Code Playgroud)
即使这样也有效(这引发了对整个 ORA-38104 检查的严重怀疑)!
merge into ET.PSEUDODELETETABLE TARGET
using (select 1 as ID, 'Horst' as NAME from sys.dual) SOURCE
on ((TARGET.ISDELETED, 'dummy') = ((1, 'dummy')) and SOURCE.ID = TARGET.ID)
when matched then
update set ISDELETED = 0, NAME = SOURCE.NAME
when not matched then
insert values (SOURCE.ID, SOURCE.NAME, 0);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
40548 次 |
最近记录: |