2012-02-17 29 views
19

Necesito actualizar una consulta para que compruebe que una entrada duplicada no exista antes de la inserción. En MySQL puedo usar INSERT IGNORE para que, si se encuentra un registro duplicado, se salte la inserción, pero parece que no puedo encontrar una opción equivalente para Oracle. ¿Alguna sugerencia?Oracle Equivalente a MySQL INSERT IGNORE?

Respuesta

23

Echa un vistazo a la instrucción MERGE. Esto debería hacer lo que quieras; es la cláusula WHEN NOT MATCHED lo que hará esto.

hacer a la falta de Oracle de apoyo para una auténtica VALORES() cláusula de la sintaxis para un único registro con valores fijos es bastante torpe sin embargo:

MERGE INTO your_table yt 
USING (
    SELECT 42 as the_pk_value, 
      'some_value' as some_column 
    FROM dual 
) t on (yt.pk = t.the_pke_value) 
WHEN NOT MATCHED THEN 
    INSERT (pk, the_column) 
    VALUES (t.the_pk_value, t.some_column); 

Un enfoque diferente (si está por ejemplo haciendo de carga a granel de una tabla diferente) es usar el recurso "Error logging" de Oracle. La declaración podría tener este aspecto:

INSERT INTO your_table (col1, col2, col3) 
SELECT c1, c2, c3 
FROM staging_table 
LOG ERRORS INTO errlog ('some comment') REJECT LIMIT UNLIMITED; 

Posteriormente todas las filas que han lanzado un error están disponibles en la tabla errlog. Debe crear esa tabla errlog (o el nombre que elija) manualmente antes de ejecutar la inserción usando DBMS_ERRLOG.CREATE_ERROR_LOG.

Consulte el manual para más detalles

+1

errores de registro todavía podrá lanzar una excepción en violaciónes de clave única o primaria, a menos que las cosas han cambiado desde: http://asktom.oracle.com/pls/apex/f?p=100:11: 0 :::: P11_QUESTION_ID: 1500471500346067777 –

+0

@ShannonSeverance: Funciona para 'INSERT's, que es lo que Bad Programmer está pidiendo. Pero gracias por el enlace no sabía que no funciona para las actualizaciones en el PK (solo lo uso para inserciones) –

+1

¿No debería reemplazarse la palabra clave 'FROM' por la palabra clave' USING'? Eche un vistazo a http://stackoverflow.com/questions/16414747/oracle-equivalent-of-insert-ignore si es necesario. – Wis

4

No creo que no hay más que para ahorrar tiempo se puede intentar la inserción e ignorar lo inevitable de error:

begin 

    insert into table_a(col1, col2, col3) 
    values (1, 2, 3); 

    exception when dup_val_on_index then 
     null; 

end; 
/

Esto sólo ignorar excepciones planteadas específicamente por clave primaria duplicado o restricciones de claves únicas; todo lo demás se levantará como normal.

Si no desea hacer esto, primero tiene que seleccionar de la tabla, que no es tan eficiente.

0

¿Qué hay de la simple adición de un índice con lo que los campos que necesita para comprobar si hay duplicados y decir que debe ser único? Guarda una verificación de lectura.

+1

Porque fallará el inserto si hay duplicados, cuando realmente es posible que solo quiera omitirlos. –

15

Si estás en 11g se puede utilizar la sugerencia IGNORE_ROW_ON_DUPKEY_INDEX:

SQL> create table my_table(a number, constraint my_table_pk primary key (a)); 

Table created. 

SQL> insert /*+ ignore_row_on_dupkey_index(my_table, my_table_pk) */ 
    2 into my_table 
    3 select 1 from dual 
    4 union all 
    5 select 1 from dual; 

1 row created. 
+0

¡gracias esto funcionó! pero parece ser una solución no estándar ... como si alguien recordara alguna vez esta notación. –

+0

@SonicSoul Tienes razón, es una forma inusual de codificar. El manual incluso señala que las sugerencias normalmente no tienen un efecto semántico. Como todos los consejos, este debe ser usado con cuidado. Por ejemplo, si la sugerencia fue mal escrita, no habría error de tiempo de compilación, la característica simplemente no funcionaría silenciosamente. –

+1

Sí, recientemente llegué al desarrollo de Oracle y estoy bastante desconcertado por la cantidad de estos trucos para lograr lo que solía pensar que eran cosas simples con sql :) –

1

Una solución sencilla

insert into t1 
    select from t2 
    where not exists 
    (select 1 from t1 where t1.id= t2.id) 
3

Otra variante

Insert into my_table (student_id, group_id) 
select distinct p.studentid, g.groupid 
from person p, group g 
where NOT EXISTS (select 1 
       from my_table a 
       where a.student_id = p.studentid 
       and a.group_id = g.groupid) 

o que podría hacer

Insert into my_table (student_id, group_id) 
select distinct p.studentid, g.groupid 
from person p, group g 
MINUS 
select student_id, group_id 
from my_table 
0

Ésta no es la mía, pero llegó en muy práctico cuando se utiliza sqlloader:

  1. crear una vista que apunta a la tabla:

    CREATE OR REPLACE VIEW test_view 
    AS SELECT * FROM test_tab 
    
  2. crear el gatillo:

    CREATE OR REPLACE TRIGGER test_trig 
    INSTEAD OF INSERT ON test_view 
    FOR EACH ROW 
        BEGIN 
        INSERT INTO test_tab VALUES 
        (:NEW.id, :NEW.name); 
        EXCEPTION 
        WHEN DUP_VAL_ON_INDEX THEN NULL; 
        END test_trig; 
    
  3. y en el archivo ctl, inserte en la vista en su lugar:

    OPTIONS(ERRORS=0) 
    LOAD DATA 
    INFILE 'file_with_duplicates.csv' 
    INTO TABLE test_view 
    FIELDS TERMINATED BY ',' 
    (id, field1) 
    
Cuestiones relacionadas