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