PLSQL Вставить в с подзапросом и возвращением предложения (Oracle) - PullRequest
19 голосов
/ 16 марта 2011

Я не могу понять правильный синтаксис для следующего псевдо-sql:

INSERT INTO some_table
           (column1,
            column2)
     SELECT col1_value, 
            col2_value 
       FROM other_table
      WHERE ...       
  RETURNING id
       INTO local_var; 

Я хотел бы вставить что-то со значениями подзапроса.После вставки мне нужен новый сгенерированный идентификатор.

Вот что говорит оракул:

Вставить заявление

Возвращение в

ОК, я думаю, что это невозможно только с предложением значений ... Есть ли альтернатива?

Ответы [ 4 ]

15 голосов
/ 16 марта 2011

Вы не можете использовать ВОЗВРАЩАЮЩИЙСЯ КОЛЛЕКТОР ИЗ ВСТАВКИ. Эта методология может работать с обновлениями и удаляет howeveer:

create table test2(aa number)
/
insert into test2(aa)
      select level
        from dual
        connect by level<100
/        

set serveroutput on
declare 
     TYPE t_Numbers IS TABLE OF test2.aa%TYPE
        INDEX BY BINARY_INTEGER;
      v_Numbers t_Numbers;
      v_count number;
begin


update test2
  set aa = aa+1
returning aa bulk collect into v_Numbers;

    for v_count in 1..v_Numbers.count loop
        dbms_output.put_line('v_Numbers := ' || v_Numbers(v_count));
    end loop;

end;

Вы можете заставить его работать с помощью нескольких дополнительных шагов (делая FORALL INSERT с использованием TREAT) как описано в этой статье:

возврат с вставкой .. выберите

T

чтобы использовать созданный ими пример и применить его к тестовой таблице test2

 CREATE or replace TYPE ot AS OBJECT
    ( aa number);
/


CREATE TYPE ntt AS TABLE OF ot;
/

set serveroutput on
 DECLARE

       nt_passed_in ntt;
       nt_to_return ntt;

       FUNCTION pretend_parameter RETURN ntt IS
          nt ntt;
       BEGIN
          SELECT ot(level) BULK COLLECT INTO nt
         FROM   dual
         CONNECT BY level <= 5;
         RETURN nt;
      END pretend_parameter;

   BEGIN

      nt_passed_in := pretend_parameter();

      FORALL i IN 1 .. nt_passed_in.COUNT
         INSERT INTO test2(aa)
         VALUES
         ( TREAT(nt_passed_in(i) AS ot).aa
         )
         RETURNING ot(aa)
         BULK COLLECT INTO nt_to_return;

      FOR i IN 1 .. nt_to_return.COUNT LOOP
         DBMS_OUTPUT.PUT_LINE(
            'Sequence value = [' || TO_CHAR(nt_to_return(i).aa) || ']'
            );
      END LOOP;

   END;
   /
14 голосов
/ 16 марта 2011

К сожалению, это невозможно.ВОЗВРАТ доступен только для операторов INSERT ... VALUES.См. эту ветку форума Oracle для обсуждения этой темы.

0 голосов
/ 16 марта 2011

Поскольку вставка основана на выборе, Oracle предполагает, что вы разрешаете многострочную вставку с этим синтаксисом. В этом случае посмотрите на многострочную версию документа возвращающего предложения, поскольку это демонстрирует, что вам нужно использовать BULK COLLECT, чтобы извлечь значение из всех вставленных строк в коллекцию результатов.

В конце концов, если ваш запрос вставки создает две строки - какое возвращаемое значение он поместит в одну переменную?

РЕДАКТИРОВАТЬ - Оказывается, это не работает, как я думал .... черт возьми!

0 голосов
/ 16 марта 2011

Это не так просто, как вы думаете, и, конечно, не так просто, как при использовании MySQL. Oracle не отслеживает последние вставки, так что вы можете проверить результат.

Вам нужно будет найти какой-то другой способ сделать это, вы можете сделать это, используя ROWID - но это имеет свои недостатки.

По этой ссылке обсуждался вопрос: http://forums.oracle.com/forums/thread.jspa?threadID=352627

...