不允许时用于替换MERGE INTO Oracle语法的模式

|| 我有一个使用Oracle MERGE INTO ... DML语句更新表A以与另一个表B中的某些更改相对应的应用程序(表A是表B所选部分的摘要以及一些其他信息)。在典型的合并操作中,可能在表B中插入5-6行(十万分之一),并更新2-3行。 事实证明,该应用程序将部署在目标表上具有安全策略的环境中。 MERGE INTO ...语句不能与这些表一起使用(ORA-28132:语法合并不支持安全策略) 因此,我们必须更改MERGE INTO ...逻辑,以改为使用常规插入和更新。这是其他人遇到的问题吗?是否存在用于将merge语句中的WHEN MATCHED / WHEN NOT MATCHED逻辑转换为INSERT和UPDATE语句的最佳实践模式?合并在存储过程中,因此,如果需要,除了DML之外,解决方案还可以使用PL / SQL。     
已邀请:
        另一种方法(合并除外)将使用两个sql语句,一个用于插入,一个用于更新。可以使用联接或\“ in \”子句来处理\“何时匹配\”和\“何时不匹配\”。 如果决定采用以下方法,最好先运行更新(正弦仅针对匹配记录运行),然后再插入非匹配记录。无论哪种方式,数据集都是相同的,它只按以下顺序更新较少的记录数。 同样,类似于“合并”,即使Source和Target中的名称匹配,此更新语句也会更新Name列。如果您不希望这样做,也可以将该条件添加到where。
create table src_table(
   id number primary key,
   name varchar2(20) not null
);

create table tgt_table(
   id number primary key,
   name varchar2(20) not null
);

insert into src_table values (1, \'abc\');
insert into src_table values (2, \'def\');
insert into src_table values (3, \'ghi\');

insert into tgt_table values (1, \'abc\');
insert into tgt_table values (2,\'xyz\');

SQL> select * from Src_Table;

        ID NAME
---------- --------------------
         1 abc
         2 def
         3 ghi

SQL> select * from Tgt_Table;

        ID NAME
---------- --------------------
         2 xyz
         1 abc

Update tgt_Table tgt
   set Tgt.Name = 
      (select Src.Name
          from Src_Table Src
          where Src.id = Tgt.id
      );

2 rows updated. --Notice that ID 1 is updated even though value did not change

select * from Tgt_Table;

   ID NAME
----- --------------------
    2 def
    1 abc

insert into tgt_Table
select src.*
  from Src_Table src,
       tgt_Table tgt
  where src.id = tgt.id(+)
    and tgt.id is null;

1 row created.

SQL> select * from tgt_Table;

        ID NAME
---------- --------------------
         2 def
         1 abc
         3 ghi

commit;
可能有更好的方法来执行此操作,但这似乎很简单且面向SQL。如果数据集很大,那么PL / SQL解决方案将不会表现出色。     
        除了深入了解安全策略外,我至少可以想到两种选择。 处理记录以逐行合并。如果更新失败,则尝试进行更新,然后插入,反之亦然,这取决于您是否希望大多数记录需要更新或插入(即针对最常见的情况进行优化,以减少触发的SQL语句的数量),例如:
begin
  for row in (select ... from source_table) loop
    update table_to_be_merged
    if sql%rowcount = 0 then -- no row matched, so need to insert
      insert ...
    end if;
  end loop;
end;
另一种选择是将要合并的记录批量收集,然后尝试批量插入它们,捕获所有主键异常(我现在无法回忆起其语法,但是可以批量插入将所有无法插入的行放入另一个数组中,然后进行处理)。 逻辑上,无论如何,合并语句必须检查幕后每个记录的存在,我认为它的处理与我上面发布的代码非常相似。但是,合并将始终比在PLSQL中编码更为有效,因为合并将只有1个SQL调用,而不是许多SQL调用。     

要回复问题请先登录注册