2012-02-17 15 views
19

Ho bisogno di aggiornare una query in modo che controlli che una voce duplicata non esiste prima dell'inserimento. In MySQL posso semplicemente usare INSERISCI IGNORE in modo che se si trova un record duplicato, salta semplicemente l'inserto, ma non riesco a trovare un'opzione equivalente per Oracle. Eventuali suggerimenti?Oracle Equivalente a MySQL INSERT IGNORA?

risposta

23

Controlla la dichiarazione MERGE. Questo dovrebbe fare ciò che vuoi: è la clausola WHEN NOT MATCHED che lo farà.

fare per mancanza di Oracle di supporto per veri valori() Clausola la sintassi per un singolo record con valori fissi è piuttosto goffo però:

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 approccio diverso (se si è per esempio facendo carico alla rinfusa da una tabella diversa) utilizza la funzione "Registrazione errori" di Oracle. La dichiarazione sarebbe simile a questa:

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

In seguito tutte le righe che avrebbe generato un errore sono disponibili nella tabella errlog. È necessario creare manualmente la tabella errlog (o qualsiasi altro nome) prima di eseguire l'inserimento utilizzando DBMS_ERRLOG.CREATE_ERROR_LOG.

consultare il manuale per i dettagli

+1

errori nel registro saranno ancora un'eccezione sulla violazione chiave univoca o primaria, a meno che le cose sono cambiate da allora: http://asktom.oracle.com/pls/apex/f?p=100:11: 0 :::: P11_QUESTION_ID: 1500471500346067777 –

+0

@ShannonSeverance: Funziona con 'INSERT's, che è ciò che sta richiedendo Bad Programmer. Ma grazie per il collegamento non ero a conoscenza del fatto che non funziona per gli aggiornamenti sul PK (lo uso solo per gli inserti) –

+1

Se la parola chiave 'FROM' non è stata sostituita dalla parola chiave' USING'? Dai un'occhiata a http://stackoverflow.com/questions/16414747/oracle-equivalent-of-insert-ignore se necessario. – Wis

4

Io non credo che ci sia, ma per risparmiare tempo è possibile tentare l'inserto e ignorare l'errore inevitabile:

begin 

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

    exception when dup_val_on_index then 
     null; 

end; 
/

Questo sarà solo ignorare le eccezioni sollevate in particolare dalla chiave primaria duplicata o vincoli di chiave unici; tutto il resto verrà sollevato normalmente.

Se non si desidera eseguire questa operazione, è necessario selezionare prima la tabella, il che non è poi così efficiente.

0

Come circa la semplice aggiunta di un indice con qualunque campi è necessario controllare per gonzi su e dire che deve essere unico? Salva un controllo di lettura.

+1

Perché questo fallirà l'inserto se ci sono duplicati, quando in realtà si potrebbe voler semplicemente saltarli. –

15

Se siete su 11g è possibile utilizzare il suggerimento 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

grazie a questo ha funzionato! ma sembra una soluzione non standard ... come se qualcuno ricordasse questa notazione. –

+0

@SonicSoul Hai ragione, è un modo insolito di codificare. Il manuale rileva anche che i suggerimenti normalmente non hanno un effetto semantico. Come tutti i suggerimenti, questo deve essere usato con attenzione. Ad esempio, se il suggerimento fosse stato scritto erroneamente, non ci sarebbe stato alcun errore in fase di compilazione, la funzione non funzionerebbe in silenzio. –

+1

sì, sono arrivato di recente allo sviluppo di Oracle e sono piuttosto sconcertato dalla quantità di questi trucchi per ottenere quello che pensavo fossero cose semplici con sql :) –

1

Una soluzione semplice

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

Un'altra 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 si potrebbe fare

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

Questo non è mia, ma è stato molto utile quando si utilizza sqlloader:

  1. creare una vista che punta al vostro tavolo:

    CREATE OR REPLACE VIEW test_view 
    AS SELECT * FROM test_tab 
    
  2. creare il grilletto:

    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. e nel file ctl, inserire invece nella vista:

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