2016-03-16 12 views
5

BiorącCzy INSERT [...] ON CONFLICT może być użyte do naruszenia klucza obcego?

=> select * from referenced; 
referenced_id | name 
---------------+------- 
      1 | one 
      2 | two 
      3 | three 

i

=> select * from entries; 
entry_id | referenced_id |  name  
----------+---------------+------------------ 
     1 |    3 | references three 

gdzie referenced_id i entry_id są klucze podstawowe.

Chcę wstawić instrukcję dla entries, która pomija wstawianie, jeśli już istnieje entry_id lub pozycja, do której nie istnieje odwołanie. Pierwszy z nich jest łatwy do wykonania:

INSERT INTO entries 
VALUES (1, 2, 'references two') 
ON CONFLICT (entry_id) DO NOTHING; 

Czy można tu również sprawdzić istnienie klucza obcego?

Odpowiedz

6

Tak, dołącz do swoich wierszy wejściowych do odpowiedniej tabeli, usuwając wiersze bez meczu na kolumnie FK:

INSERT INTO entries(entry_id, referenced_id, name) 
SELECT val.entry_id, val.referenced_id, val.name 
FROM (
    VALUES (1, 2, 'references two') 
     -- more? 
) val (entry_id, referenced_id, name) 
JOIN referenced USING (referenced_id) -- drop rows without matching FK 
ON  CONFLICT (entry_id) DO NOTHING; -- drop rows with duplicate id 

Sam (INSERT ... ON CONFLICT DO NOTHING) upsert reaguje tylko na unikalnych naruszeń. The manual:

ON CONFLICT mogą być użyte do określenia alternatywnego działania mające na celu podniesienie unikalny błąd naruszenia ograniczenia lub wyłączenia wiązania. (Patrz ON CONFLICT Clause poniżej.)

+0

To działa bardzo ładnie, bardzo doceniane. Dziękuję również za wyjaśnienie dotyczące klauzuli "ON CONFLICT". – peterwimsey

+0

Czy ta praca przy wstawianiu do tej samej tabeli próbuję się odwoływać? więc coś w stylu 'INSERT INTO entries ... JOIN entries'? –

+2

@JuanCarlosOropeza: Możesz dołączyć do tej samej tabeli w ten sam sposób, po prostu upewnij się, że warunek łączenia może pasować tylko do * pojedynczego * wiersza. W przeciwnym razie musisz użyć innej techniki. –

Powiązane problemy