2008-09-25 11 views
12

Tengo una serie de tablas de valores de código que contienen un código y una descripción con una Identificación larga.Oracle Insertar a través de Seleccionar de varias tablas donde una tabla puede no tener una fila

ahora quiero crear una entrada para un tipo de cuenta que hace referencia a una serie de códigos, así que tener algo como esto:

insert into account_type_standard (account_type_Standard_id, 
tax_status_id, recipient_id) 
(select account_type_standard_seq.nextval, 
ts.tax_status_id, r.recipient_id 
from tax_status ts, recipient r 
where ts.tax_status_code = ? 
and r.recipient_code = ?) 

Esto recupera los valores apropiados de las tablas tax_status y destinatario si es un partido se encuentra para sus respectivos códigos. Desafortunadamente, recipient_code es anulable, y por lo tanto el? el valor de sustitución podría ser nulo. Por supuesto, la combinación implícita no devuelve una fila, por lo que una fila no se inserta en mi tabla.

He intentado usar NVL en? y en el r.recipient_id.

He intentado forzar una combinación externa en r.recipient_code =? agregando (+), pero no es una unión explícita, por lo que Oracle aún no agregó otra fila.

¿Alguien sabe de una manera de hacer esto?

Obviamente puedo modificar la declaración para que haga la búsqueda del recipient_id externamente, y tengo un? en lugar de r.recipient_id, y no seleccione nada de la tabla de destinatarios, pero preferiría hacer todo esto en 1 declaración de SQL.

Respuesta

22

Las uniones externas no funcionan "como se esperaba" en ese caso porque le indicó explícitamente a Oracle que solo quiere datos si coinciden los criterios de esa tabla. En ese escenario, la unión externa se vuelve inútil.

un trabajo en torno

INSERT INTO account_type_standard 
    (account_type_Standard_id, tax_status_id, recipient_id) 
VALUES( 
    (SELECT account_type_standard_seq.nextval FROM DUAL), 
    (SELECT tax_status_id FROM tax_status WHERE tax_status_code = ?), 
    (SELECT recipient_id FROM recipient WHERE recipient_code = ?) 
) 

[Editar] Si espera múltiples filas de una sub-select, se puede añadir ROWNUM = 1 a cada cláusula where o usar un agregado tal como MAX o MIN. Esto, por supuesto, puede no ser la mejor solución para todos los casos.

[Editar] Per comentario,

(SELECT account_type_standard_seq.nextval FROM DUAL), 

puede ser sólo

account_type_standard_seq.nextval, 
+0

no Will esto tiene un problema es que hay múltiples entradas en tax_status o en el destinatario y lo que ocurre con NULL recip ient_code? –

+0

Acabo de probarlo, y el código de destinatario nulo da como resultado nulo para la columna recipient_id en account_type_standard. No sé sobre entradas múltiples, pero en mi caso, las tablas tienen códigos únicos, así que estoy bien. – Mikezx6r

+0

Según Tony Andrews, no es necesario seleccionar de DUAL para el valor de secuencia. Puede simplemente tener account_type_standard_seq.nextval. – Mikezx6r

3

No estaba claro para mí en la pregunta de si ts.tax_status_code es una clave principal o suplente, o no. Lo mismo con recipient_code. Esto sería útil para saber

Puede tratar con la posibilidad de que su variable de vinculación sea nula utilizando un OR de la siguiente manera. Deberías unir lo mismo a las primeras dos variables de vinculación.

Si le preocupa el rendimiento, sería mejor comprobar si los valores que intenta enlazar son nulos o no y, a continuación, emitir una instrucción SQL diferente para evitar el OR.

insert into account_type_standard 
(account_type_Standard_id, tax_status_id, recipient_id) 
(
select 
    account_type_standard_seq.nextval, 
    ts.tax_status_id, 
    r.recipient_id 
from tax_status ts, recipient r 
where (ts.tax_status_code = ? OR (ts.tax_status_code IS NULL and ? IS NULL)) 
and (r.recipient_code = ? OR (r.recipient_code IS NULL and ? IS NULL)) 
+0

¿Esta consulta no tiene potencial para ser muy lenta? –

+1

Sí, de ahí mi afirmación sobre "Si le preocupa el rendimiento ..." –

3

Probar:

insert into account_type_standard (account_type_Standard_id, tax_status_id, recipient_id) 
select account_type_standard_seq.nextval, 
     ts.tax_status_id, 
     (select r.recipient_id 
     from recipient r 
     where r.recipient_code = ? 
     ) 
from tax_status ts 
where ts.tax_status_code = ? 
+0

¿Sabe si esto es más eficiente que la respuesta de Oglester? Si es así, puedo ser influenciado para aceptar esta respuesta. De lo contrario, creo que tener todos los seleccionados en sus respectivas ubicaciones es más claro que tener una cláusula larga de from y where. Sé que eso es lo que tenía, pero ... – Mikezx6r

+0

No creo que sea significativamente mejor (o peor). Sin embargo, la solución de Oglester no requiere la selección de DUAL - He publicado una nueva respuesta que muestra una versión modificada (solo * un poco * más eficiente) –

7

Una versión ligeramente simplificada de la solución de Oglester (la secuencia no requiere una Selecciona de DUAL:

INSERT INTO account_type_standard 
    (account_type_Standard_id, tax_status_id, recipient_id) 
VALUES( 
    account_type_standard_seq.nextval, 
    (SELECT tax_status_id FROM tax_status WHERE tax_status_code = ?), 
    (SELECT recipient_id FROM recipient WHERE recipient_code = ?) 
) 
-2
insert into received_messages(id, content, status) 
    values (RECEIVED_MESSAGES_SEQ.NEXT_VAL, empty_blob(), ''); 
1
insert into account_type_standard (account_type_Standard_id, tax_status_id, recipient_id) 
select account_type_standard_seq.nextval, 
    ts.tax_status_id, 
    (select r.recipient_id 
    from recipient r 
    where r.recipient_code = ? 
    ) 
from tax_status ts 
where ts.tax_status_code = ? 
+2

Por favor, no publique solo el código de las respuestas. – Ren

Cuestiones relacionadas