不允许时替换为合并到Oracle语法的模式

不允许时替换为合并到Oracle语法的模式,oracle,dml,security-policy,Oracle,Dml,Security Policy,我有一个应用程序使用Oracle合并到。。。DML语句更新表A,以与另一个表B中的某些更改相对应(表A是表B中选定部分以及其他一些信息的汇总)。在典型的合并操作中,可能会在表B中插入5-6行(千行中的10行),并更新2-3行 事实证明,应用程序将部署在目标表上具有安全策略的环境中。合并成。。。语句不能与这些表一起使用(ORA-28132:Merge-into语法不支持安全策略) 所以我们必须将合并更改为。。。使用常规插入和更新的逻辑。这是其他人遇到的问题吗?是否有最佳实践模式将merge语句中的

我有一个应用程序使用Oracle合并到。。。DML语句更新表A,以与另一个表B中的某些更改相对应(表A是表B中选定部分以及其他一些信息的汇总)。在典型的合并操作中,可能会在表B中插入5-6行(千行中的10行),并更新2-3行

事实证明,应用程序将部署在目标表上具有安全策略的环境中。合并成。。。语句不能与这些表一起使用(ORA-28132:Merge-into语法不支持安全策略)


所以我们必须将合并更改为。。。使用常规插入和更新的逻辑。这是其他人遇到的问题吗?是否有最佳实践模式将merge语句中的WHEN MATCHED/WHEN NOT MATCHED逻辑转换为INSERT和UPDATE语句?合并是在一个存储过程中进行的,因此,如果需要的话,解决方案可以在DML之外使用PL/SQL。

除了深入研究安全策略之外,我至少可以考虑两个选项,我对安全策略了解不多

处理记录以逐行合并。尝试执行更新,如果更新失败,则插入,反之亦然,这取决于您是否期望大多数记录需要更新或插入(即针对最常见的情况进行优化,以减少触发的SQL语句数),例如:

另一种选择可能是批量收集要合并到数组中的记录,然后尝试批量插入它们,捕获所有主键异常(我现在记不起这方面的语法,但您可以通过批量插入将所有插入失败的行放置到另一个数组中,然后处理它们)

从逻辑上讲,merge语句必须检查每个记录在幕后是否存在,我认为它的处理方式与我上面发布的代码非常类似。然而,合并总是比在PLSQL中编码它更有效,因为它只需要一个SQL调用,而不是许多

另一种方法(除了Merge)是使用两条sql语句,一条用于insert,另一条用于update。“匹配时”和“不匹配时”可以使用联接或“in”子句处理

如果您决定采用以下方法,最好先运行更新(因为它只针对匹配的记录运行),然后插入不匹配的记录。无论哪种方式,数据集都是相同的,它只是按照下面的顺序更新较少的记录

此外,与Merge类似,即使源和目标中的名称匹配,此update语句也会更新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解决方案的性能就不会那么好。

使用外部联接时,
insert
的效率不是很高。最好使用
不在(…)
不存在(…)
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;