PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Co dzieje się z duplikatami podczas wstawiania wielu wierszy?

INSERT po prostu wstawi wszystkie wiersze i nic wydarzy się coś wyjątkowego, chyba że masz jakieś ograniczenie zabranianie duplikatów / nakładających się wartości (PRIMARY KEY , UNIQUE , CHECK lub EXCLUDE ograniczenie) – o których nie wspomniałeś w swoim pytaniu. Ale prawdopodobnie właśnie o to się martwisz.

Zakładając UNIQUE lub ograniczenie PK na (col1,col2) , masz do czynienia z podręcznikiem UPSERT sytuacja. Wiele powiązanych pytań i odpowiedzi, które można znaleźć tutaj.

Ogólnie, jeśli jakikolwiek Ograniczenie jest naruszone, zgłoszony jest wyjątek, który (chyba że jest uwięziony w podtransakcji, jak to jest możliwe w proceduralnym języku po stronie serwera, takim jak plpgsql) wycofa nie tylko instrukcję, ale całą transakcję .

Bez równoczesnych zapisów

Np. Żadna inna transakcja nie będzie próbowała pisać do tej samej tabeli w tym samym czasie.

  • Wyklucz wiersze, które są już w tabeli z WHERE NOT EXISTS ... lub jakakolwiek inna stosowna technika:

  • Wybierz wiersze, których nie ma w innej tabeli

  • I nie zapomnij usunąć duplikatów w również wstawiony zestaw, co nie być wykluczone przez semi-anti-join WHERE NOT EXISTS ...

Jedną z technik radzenia sobie z obydwoma na raz jest EXCEPT :

INSERT INTO tbl (col1, col2)
VALUES
  (text 'v1', text 'v2')  -- explicit type cast may be needed in 1st row
, ('v3', 'v4')
, ('v3', 'v4')  -- beware of dupes in source
EXCEPT SELECT col1, col2 FROM tbl;

EXCEPT bez słowa kluczowego ALL zgina zduplikowane wiersze w źródle. Jeśli wiesz, że nie ma duplikatów lub nie chcesz po cichu składać duplikatów, użyj EXCEPT ALL (lub jedną z innych technik). Zobacz:

  • Używanie klauzuli EXCEPT w PostgreSQL

Ogólnie, jeśli tabela docelowa jest duża , WHERE NOT EXISTS w połączeniu z DISTINCT na źródle prawdopodobnie będzie szybciej:

INSERT INTO tbl (col1, col2)
SELECT *
FROM  (
   SELECT DISTINCT *
   FROM  (
       VALUES
         (text 'v1', text'v2')
       , ('v3', 'v4')
       , ('v3', 'v4')  -- dupes in source
      ) t(c1, c2)
   ) t
WHERE NOT EXISTS (
   SELECT FROM tbl
   WHERE  col1 = t.c1 AND col2 = t.c2
   );

Jeśli może być wiele duplikatów, opłaca się najpierw złożyć je w źródle. W przeciwnym razie użyj jednego podzapytania mniej.

Powiązane:

  • Wybierz wiersze, których nie ma w innej tabeli

Z równoczesnymi zapisami

Użyj UPSERT Postgresa implementacja INSERT ... ON CONFLICT ... w Postgresie 9.5 lub później:

INSERT INTO tbl (col1,col2)
SELECT DISTINCT *  -- still can't insert the same row more than once
FROM  (
   VALUES
     (text 'v1', text 'v2')
   , ('v3','v4')
   , ('v3','v4')  -- you still need to fold dupes in source!
  ) t(c1, c2)
ON CONFLICT DO NOTHING;  -- ignores rows with *any* conflict!

Dalsza lektura:

  • Jak używać RETURNING z ON CONFLICT w PostgreSQL?
  • Jak wstawić wiersz zawierający klucz obcy?

Dokumentacja:

  • Instrukcja
  • Strona zatwierdzenia
  • Strona Wiki Postgres

Referencyjna odpowiedź Craiga dla UPSERT problemy:

  • Jak UPSERT (MERGE, INSERT... W DUPLIKACIE AKTUALIZACJI) w PostgreSQL?


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kolumna dynamiczna w postgresie instrukcji SELECT

  2. Now() bez strefy czasowej

  3. Heroku Rails 4 nie może połączyć się z serwerem:połączenie odrzucone

  4. GROUP BY w klauzuli UPDATE FROM

  5. Wykonywanie zmian topologii replikacji dla PostgreSQL