2011-03-16 34 views
16

I no se puede averiguar la sintaxis correcta para el siguiente pseudo-sql:PLSQL Insert into con subconsulta y cláusula de regresar (Oracle)

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

me gustaría insertar algo con los valores de una subconsulta. Después de insertar, necesito el nuevo ID generado.

Esto es lo oráculo doc dice:

Insert Statement

Returning Into

bien creo que no es posible sólo con la cláusula de valores ... ¿Existe una alternativa?

Respuesta

14

No se puede usar el RETURNING BULK COLLECT de un INSERT. Esta metodología puede trabajar con actualizaciones y eliminaciones 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; 

Puede conseguir que funcione con unos pocos pasos adicionales (haciendo una golosina FORALL INSERT que utiliza) como se describe en este artículo:

returning with insert..select

T

para utilizar el ejemplo que crean y aplicarlo a la tabla de prueba 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; 
/
+0

+1 ¡Gran ejemplo! –

+0

¡Eso es genial! El único problema que me queda es declarar los tipos de objetos. No es posible declarar tipos de objetos en un paquete ... –

-2

Esto no es tan fácil como puede parecer, y ciertamente no es tan fácil como lo está utilizando MySQL. Oracle no realiza un seguimiento de los últimos insertos, de forma que puede hacer ping al resultado.

Usted tendrá que trabajar a cabo alguna otra forma de hacer esto, puede hacerlo utilizando ROWID - pero esto tiene sus trampas.

Este enlace examinó la cuestión: http://forums.oracle.com/forums/thread.jspa?threadID=352627

+0

Eso no es realmente relevante a la pregunta - no se trataba de la identificación de la última fila insertada por cualquier sesión, se trataba de devolver un conjunto de valores de una instrucción INSERT específica. –

0

Debido a que la inserción se basa en una selección, Oracle está asumiendo que usted está permitiendo una de múltiples filas insertar con la sintaxis. En ese caso, observe la versión de múltiples filas del documento de la cláusula de retorno, ya que demuestra que debe usar BULK COLLECT para recuperar el valor de todas las filas insertadas en una colección de resultados.

Después de todo, si su consulta de inserción crea dos filas - que volvió valor tendría que poner en una variable única?

EDITAR - Resulta que esto no funciona como yo había pensado .... caray!

+0

Lo intenté pero recibí un ORA 009333. El comando SQL no finalizó correctamente después de where. tipo de colección es una buena idea. –

+0

Como dijo Tony en su respuesta, BULK COLLECT no funciona con INSERT, al menos en 10g o antes. No tengo claro si esto ha cambiado en 11g. –

+0

sí, pensé que funcionaba, pero parece que no funciona. Perdón por el mal consejo. –

11

Desafortunadamente eso no es posible. RETURNING solo está disponible para las sentencias INSERT ... VALUES. Vea this Oracle forum thread para una discusión sobre este tema.

+0

+1 por ser correcto –

Cuestiones relacionadas