Можно ли вернуть первичный ключ на операторе вставки как select - Oracle? - PullRequest
1 голос
/ 24 февраля 2020

Поэтому при использовании триггера я обычно получаю первичный ключ новой вставленной записи следующим образом:

вставка в таблицу значений (pk1, notes) (ноль, «тестер»), возвращая pk1 into v_item;

Я пытаюсь использовать ту же концепцию, но с использованием вставки с использованием оператора select. Так, например:

вставка в таблицу1 (pk1, заметки) выберите ноль, описание из таблицы2, где pk2 = 2, возвращая pk1 в v_item;

Примечание:
1. В table1 есть триггер, который автоматически создает pk1 при вставке.
2. Мне нужно использовать select insert из-за размера вставляемой таблицы.
3. Вставка в основном является копией записи, поэтому за один раз вставляется только 1 запись.

Дайте мне знать, могу ли я предоставить больше информации.

Ответы [ 2 ]

2 голосов
/ 24 февраля 2020

Вы не можете использовать этот механизм; как показано в документации схема железной дороги:

insert syntax

возвращаемое предложение допускается только для версии значений, но не для версии подзапроса.

Я интерпретирую ваше второе ограничение (относительно «размера таблицы») как количество столбцов, которое вы должны обработать, возможно, как отдельные переменные, а не количество строк - я не понимаю, как это будет быть актуальным здесь. Есть способы избежать использования множества локальных переменных для каждого столбца; Вы можете сначала выбрать переменную типа строки:

declare
  v_item number;
  v_row table1%rowtype;
begin
  ...
  select null, description
  into v_row
  from table2 where pk2 = 2;

  insert into table1 values v_row returning pk1 into v_item;

  dbms_output.put_line(v_item);
  ...

или с помощью al oop, что может сделать вещи более сложными, чем необходимо, если у вас действительно есть только одна строка:

declare
  v_item number;
begin
  ...
  for r in (
    select description
    from table2 where pk2 = 2
  )
  loop
    insert into table1 (notes) values (r.description) returning pk1 into v_item;
    dbms_output.put_line(v_item);
    ...
  end loop;
  ...

или с коллекцией ... как @Dan опубликовал, пока я отвечал, так что я не буду повторяться! - хотя, опять же, это может быть излишним или слишком сложным для одного ряда.

2 голосов
/ 24 февраля 2020

Я не верю, что вы можете сделать это с помощью вставки / выбора напрямую. Тем не менее, вы можете сделать это с PL / SQL и FORALL. Учитывая ограничение размера таблицы, вам придется сбалансировать использование памяти с производительностью, используя l_limit. Вот пример ...

Учитывая эту таблицу из 100 строк:

create table t (
  c  number generated by default as identity,
  c2 number
);

insert into t (c2)
select rownum
from dual
connect by rownum <= 100;

Вы можете сделать это:

declare

  cursor t_cur
  is
    select c2
    from t;

  type t_ntt is table of number;

  l_c2_vals_in t_ntt;
  l_c_vals_out t_ntt;
  l_limit      number := 10;

begin

  open t_cur;

  loop
    fetch t_cur bulk collect into l_c2_vals_in limit l_limit;

    forall i in indices of l_c2_vals_in
    insert into t (c2) values (l_c2_vals_in(i))
    returning c bulk collect into l_c_vals_out;

    -- You have access to the new ids here
    dbms_output.put_line(l_c_vals_out.count);

    exit when l_c2_vals_in.count < l_limit;
  end loop;

  close t_cur;

end;
...