Преодоление ограничения на массовые вставки по ссылке в базе данных
Кажется, что есть ограничение реализации, которое запрещает использование forall .. insert
в Oracle, когда используется через ссылку на базу данных. Это простой пример для демонстрации:
connect schema/password@db1
create table tmp_ben_test (
a number
, b number
, c date
, constraint pk_tmp_ben_test primary key (a, b)
);
Table created.
connect schema/password@db2
Connected.
declare
type r_test is record ( a number, b number, c date);
type t__test is table of r_test index by binary_integer;
t_test t__test;
cursor c_test is
select 1, level, sysdate
from dual
connect by level <= 10
;
begin
open c_test;
fetch c_test bulk collect into t_test;
forall i in t_test.first .. t_test.last
insert into tmp_ben_test@db1
values t_test(i)
;
close c_test;
end;
/
Очень смущает, что это не удается в 9i со следующей ошибкой:
ОШИБКА в строке 1: ORA-01400: невозможно вставить NULL в ("SCHEMA"."TMP_BEN_TEST"."A") ORA-02063: предыдущая строка из DB1 ORA-06512: в строке 18
Если только после проверки в 11g я понял, что это ограничение реализации.
ОШИБКА в строке 18: ORA-06550: строка 18, столбец 4: PLS-00739: FORALL INSERT/UPDATE/DELETE не поддерживается в удаленных таблицах
Действительно очевидный способ обойти это изменить forall ..
чтобы:
for i in t_test.first .. t_test.last loop
insert into tmp_ben_test@db1
values t_test(i);
end loop;
но я бы предпочел сохранить его до одной вставки, если это вообще возможно. Том Кайт предлагает использовать глобальную временную таблицу. Вставка данных в GTT, а затем по каналу связи с БД выглядит огромным перебором для набора данных, который уже имеет пользовательский тип.
Просто пояснить этот пример чрезвычайно просто по сравнению с тем, что на самом деле происходит. Мы никак не сможем сделать простой insert into
и нет никакого способа, которым все операции могли бы быть сделаны на GTT. Большие части кода должны быть выполнены в пользовательском типе.
Есть ли другой, более простой или менее DMLy способ обойти это ограничение?
2 ответа
С какими ограничениями вы сталкиваетесь в удаленной базе данных? Если вы можете создавать объекты там, у вас есть обходной путь: в удаленной базе данных создайте тип коллекции и процедуру, которая принимает коллекцию в качестве параметра и выполняет инструкцию FORALL.
Если вы создадите тип t__test/r_test в db2, а затем создадите для них общий синоним для db1, то вы сможете вызвать процедуру из db1 в db2, заполнив таблицу t_table и вернувшись в db1. Тогда вы сможете вставить в локальную таблицу.
Я предполагаю, что вы будете использовать упакованные типы и процедуры в реальном мире, а не анонимные блоки.
Кроме того, это не было бы идеальным решением для больших наборов данных, тогда GTT или подобное было бы лучше.