web-dev-qa-db-fra.com

PLSQL Insertion dans avec sous-requête et clause de retour (Oracle)

Je n'arrive pas à comprendre la syntaxe correcte pour le pseudo-SQL suivant:

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

Je voudrais insérer quelque chose avec les valeurs d'une sous-requête. Après l'insertion, j'ai besoin du nouvel identifiant généré.

Voici ce que dit le doc Oracle:

Insérer une déclaration

Retour dans

OK, je pense que ce n'est pas possible uniquement avec la clause values ​​... Y a-t-il une alternative?

18
Stephan Schielke

Vous ne pouvez pas utiliser le RETURNING BULK COLLECT à partir d'un INSERT. Cette méthodologie peut fonctionner avec des mises à jour et des suppressions:

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;

Vous pouvez le faire fonctionner avec quelques étapes supplémentaires (faire un FORALL INSERT en utilisant TREAT) Comme décrit dans cet article:

retour avec insert..select

T

utiliser l'exemple qu'ils créent et l'appliquer à la table de test 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;
   /
15
Harrison

Malheureusement ce n'est pas possible. RETURNING n'est disponible que pour les instructions INSERT ... VALUES. Voir ce fil de discussion Oracle pour une discussion à ce sujet.

13
Tony Andrews

Comme l'insertion est basée sur une sélection, Oracle suppose que vous autorisez une insertion de plusieurs lignes avec cette syntaxe. Dans ce cas, examinez la version à plusieurs lignes du document de clause de retour car elle montre que vous devez utiliser BULK COLLECT pour récupérer la valeur de toutes les lignes insérées dans une collection de résultats.

Après tout, si votre requête d’insertion crée deux lignes, quelle valeur retournée mettrait-elle dans une seule variable? 

EDIT - Il s'avère que cela ne fonctionne pas comme je l'avais pensé .... sacrément!

0
Michael Broughton