2012-02-17 15 views
19

Muszę zaktualizować zapytanie, aby sprawdzało, czy duplikat nie istnieje przed wstawieniem. W MySQL mogę po prostu użyć INSERT IGNORE, więc jeśli znajdzie się duplikat, to po prostu pominie wstawkę, ale nie mogę znaleźć odpowiednika dla Oracle. Jakieś sugestie?Oracle równoważne z MySQL INSERT IGNORE?

Odpowiedz

23

Sprawdź instrukcję MERGE. Powinno to zrobić, co chcesz - jest to klauzula WHEN NOT MATCHED, która to zrobi.

uwagi na brak Oracle wsparcia dla prawdziwego wartości() Klauzula składni dla pojedynczego rekordu ze stałymi wartościami jest dość niezdarny choć:

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); 

Inne podejście (jeśli np robi luzem załadunek z inna tabela) jest użycie funkcji "Rejestrowanie błędów" w Oracle. Oświadczenie będzie wyglądać następująco:

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

Następnie wszystkie wiersze, które zostały rzucone błąd dostępne są w tabeli errlog. Trzeba ręcznie utworzyć tabelę (lub dowolną nazwę) przed uruchomieniem wstawki przy użyciu DBMS_ERRLOG.CREATE_ERROR_LOG.

Zobacz instrukcję szczegóły

+1

błędy dziennika będzie nadal wyjątek na unikalnych lub łamania podstawowych kluczowych, chyba wiele się zmieniło od: http://asktom.oracle.com/pls/apex/f?p=100:11: 0 :::: P11_QUESTION_ID: 1500471500346067777 –

+0

@ShannonSeverance: To działa dla 'INSERT's czyli co Bad Programista prosi. Ale dzięki za link nie był świadomy, że to nie działa do aktualizacji na PK (używam go tylko do wkładek) –

+1

Should'nt Opcja 'FROM' kluczowe zostać zastąpione przez' USING' hasła? Zajrzyj na http://stackoverflow.com/questions/16414747/oracle-equivalent-of-insert-ignore w razie potrzeby. – Wis

4

Nie sądzę, istnieje tylko zaoszczędzić czas można próbować wkładkę i ignorować nieunikniony błąd:

begin 

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

    exception when dup_val_on_index then 
     null; 

end; 
/

To będzie tylko ignorować wyjątki podniesione przez specjalnie duplikatu klucza podstawowego lub unikalnych kluczowych ograniczeń; wszystko inne zostanie podniesione jak zwykle.

Jeśli nie chcesz tego robić, musisz najpierw wybrać z tabeli, która nie jest tak skuteczna.

0

Jak o po prostu dodanie indeksu ze cokolwiek pól trzeba sprawdzić powtórzeń na i powiedzieć to musi być wyjątkowa? Zapisuje sprawdzenie odczytu.

+1

Ponieważ to nie powiedzie się wstawić, jeśli istnieją duplikaty, kiedy naprawdę może po prostu chcesz je pominąć. –

15

Jeśli jesteś na 11g można skorzystać z podpowiedzi 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

dzięki temu zadziałało! ale wydaje się takie niestandardowe rozwiązanie .. jak każdy będzie kiedykolwiek pamiętać ten zapis. –

+0

@SonicSoul Masz rację, to jest niezwykły sposób kodowania. W instrukcji zauważono również, że podpowiedzi normalnie nie mają efektu semantycznego. Podobnie jak wszystkie wskazówki, ten musi być używany ostrożnie. Na przykład, jeśli wskazówka została błędnie napisana, nie wystąpiłby błąd czasu kompilacji, funkcja po prostu nie działałaby po cichu. –

+1

Tak, niedawno przybył do rozwoju Oracle i jestem dość zaskoczony ilością tych sztuczek, aby osiągnąć to, co myślałem, były proste rzeczy z SQL :) –

1

proste rozwiązanie

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

Inny wariant

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) 

czy można zrobić

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

To nie jest moja, ale przyszedł w bardzo przydatne podczas korzystania sqlloader:

  1. utworzyć widok, który wskazuje na stole:

    CREATE OR REPLACE VIEW test_view 
    AS SELECT * FROM test_tab 
    
  2. utworzyć wyzwalacz:

    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. oraz w pliku ctl, wstaw do widoku zamiast:

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