2011-04-05 23 views
22

Tengo un puñado de consultas SQL primas para SQL Server que utilizan SCOPE_IDENTITY para recuperar el ID generado por un inserto específico inmediatamente después de que INSERT se produce en una única realización ...Inserción en Oracle y la recuperación de la secuencia generada ID

INSERT into Batch(
BatchName, 
BatchType, 
Source, 
Area 
) Values (
@strBatchName, 
@strType, 
@strSource, 
@intArea 
); 

SELECT SCOPE_IDENTITY() BatchID; 

La pregunta es:

¿Cuál es la mejor manera de hacerlo para una base de datos Oracle?

¿Se puede hacer esto en Oracle a través de SQL estándar o tengo que cambiar esto para usar un procedimiento almacenado y colocar algo similar en el cuerpo del proceso almacenado?

Si debe ser un proceso almacenado, ¿cuál es la forma estándar de facto para recuperar el último número de secuencia generado, teniendo en cuenta que probablemente habrá ejecuciones superpuestas en varios hilos por lo que este mecanismo tendrá que recuperar el ID generado correctamente y no necesariamente la última ID generada.

Si dos se ejecutan simultáneamente, cada uno debe devolver la ID generada correcta de cada llamada respectiva. Tenga en cuenta que no estoy usando "@@ IDENTITY" de SQL Server debido a la naturaleza multiproceso de las llamadas.

Preferiría mantenerlo como SQL sin formato si es posible, ya que es mucho más fácil para mí administrarlo en todas las plataformas (archivo único que contiene el bloque SQL de cada plataforma separado por las etiquetas de identificación DBMS). Los procesos almacenados me resultan un poco más difíciles de manejar, pero puedo hacerlo de la única manera posible.

+0

Esas son algunas de las mejores respuestas. Ahora que estoy llegando a la tarea parece otra capa usando un "paquete", colocar un cursor en "ROWTYPE" y devolver algunos de los datos a través de un procedimiento o función * dentro del paquete * será el último paso para devolver los datos como un conjunto de resultados para que la persona que llama pueda realizar un SELECCIONAMIENTO pero pasar los datos que se deben insertar como parámetros a la función paquete. Nuevo para él, así que espero que todo tenga sentido. – Allbite

Respuesta

27

Ampliando un poco las respuestas de @Guru y @Ronnis, puede ocultar la secuencia y hacer que parezca más un autoincremento usando un desencadenador, y tener un procedimiento que haga la inserción por usted y devuelva el generado ID como un parámetro de salida.

create table batch(batchid number, 
    batchname varchar2(30), 
    batchtype char(1), 
    source char(1), 
    intarea number) 
/

create sequence batch_seq start with 1 
/

create trigger batch_bi 
before insert on batch 
for each row 
begin 
    select batch_seq.nextval into :new.batchid from dual; 
end; 
/

create procedure insert_batch(v_batchname batch.batchname%TYPE, 
    v_batchtype batch.batchtype%TYPE, 
    v_source batch.source%TYPE, 
    v_intarea batch.intarea%TYPE, 
    v_batchid out batch.batchid%TYPE) 
as 
begin 
    insert into batch(batchname, batchtype, source, intarea) 
    values(v_batchname, v_batchtype, v_source, v_intarea) 
    returning batchid into v_batchid; 
end; 
/

A continuación, puede llamar al procedimiento en lugar de hacer una inserción simple, p. Ej. desde un bloque anónimo:

declare 
    l_batchid batch.batchid%TYPE; 
begin 
    insert_batch(v_batchname => 'Batch 1', 
     v_batchtype => 'A', 
     v_source => 'Z', 
     v_intarea => 1, 
     v_batchid => l_batchid); 
    dbms_output.put_line('Generated id: ' || l_batchid); 

    insert_batch(v_batchname => 'Batch 99', 
     v_batchtype => 'B', 
     v_source => 'Y', 
     v_intarea => 9, 
     v_batchid => l_batchid); 
    dbms_output.put_line('Generated id: ' || l_batchid); 
end; 
/

Generated id: 1 
Generated id: 2 

Puede realizar la llamada sin un bloqueo anónimo explícito, p.desde SQL * Plus:

variable l_batchid number; 
exec insert_batch('Batch 21', 'C', 'X', 7, :l_batchid); 

... y utilice la variable de vinculación :l_batchid para referirse al valor generado después:

print l_batchid; 
insert into some_table values(:l_batch_id, ...); 
+0

He estado evitando los disparadores a nivel de fila desde 8i debido a problemas de rendimiento cuando hago inserciones más grandes, pero también tengo que admitir que no lo he probado desde entonces. ¿Cómo funciona con 11g o digamos 10g? – Ronnis

+0

@Ronnis: no los he usado con inserciones de lotes grandes lo suficiente como para comentar. No tenía conocimiento de ningún problema, pero supongo que el cambio de contexto (tener que seleccionar desde dual) puede ser significativo en algunas circunstancias. Y supongo que el disparador es bastante inútil si siempre haces la inserción del procedimiento de todos modos, así que esto es un poco complicado ... –

18

No hay funciones de incremento automático en Oracle para una columna. Necesita crear un objeto SEQUENCE. Puede usar la secuencia como:

insert into table(batch_id, ...) values(my_sequence.nextval, ...) 

... para devolver el número siguiente. Para averiguar el último nr secuencia creada (en la sesión), se debería utilizar:

my_sequence.currval 

This site tiene varios ejemplos completos sobre el uso de secuencias.

11

Hacerlo como un procedimiento almacenado tiene muchas ventajas. Puede obtener la secuencia que se inserta en la tabla utilizando la sintaxis insert into table_name values returning.

igual:

declare 
some_seq_val number; 
lv_seq  number; 
begin 
some_seq_val := your_seq.nextval; 
insert into your_tab (col1, col2, col3) 
values (some_seq_val, val2, val3) returning some_seq_val into lv_seq; 

dbms_output.put_line('The inserted sequence is: '||to_char(lv_seq)); 
end; 
/

O simplemente volver some_seq_val. En caso de que no esté haciendo uso de SEQUENCE, y al llegar la secuencia en algún cálculo, puede hacer uso de returning into efectivamente.

+4

Ni siquiera necesitas tantos pasos; no hay punto que declare 'some_seq', puede hacer' insert into your_tab (col1, col2, col3) values ​​(your_seq.next_val, val2, val3) devolviendo col1 a lv_seq; '. También vale la pena señalar que puede poner el valor de retorno directamente en un parámetro 'out'. –

9

Usted puede utilizar la instrucción siguiente para obtener el identificador insertado en una variable como una cosa

INSERT INTO YOUR_TABLE(ID) VALUES ('10') returning ID into :Inserted_Value; 

Ahora se puede recuperar el valor utilizando la siguiente declaración

SELECT :Inserted_Value FROM DUAL; 
0

Usted puede hacer esto con una sola declaración - si se asume que está llamando desde un conector JDBC-como con la funcionalidad de entrada/salida parámetros :

insert into batch(batchid, batchname) 
values (batch_seq.nextval, 'new batch') 
returning batchid into :l_batchid; 

o, como una secuencia de comandos PL-SQL:

variable l_batchid number; 

insert into batch(batchid, batchname) 
values (batch_seq.nextval, 'new batch') 
returning batchid into :l_batchid; 

select :l_batchid from dual; 
Cuestiones relacionadas