PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Какво се случва с дубликатите при вмъкване на няколко реда?

INSERT просто ще вмъкне всички редове и нищо ще се случи специално,освен ако имате някакъв вид ограничение забраняване на дублиращи се/припокриващи се стойности (PRIMARY KEY , UNIQUE , CHECK или EXCLUDE ограничение) - което не споменахте във вашия въпрос. Но това вероятно ви тревожи.

Приемайки UNIQUE или PK ограничение на (col1,col2) , имате работа с учебник UPSERT ситуация. Тук можете да намерите много свързани въпроси и отговори.

Като цяло, ако някакви ограничението е нарушено, се създава изключение, което (освен ако не е попаднало в подтранзакция, както е възможно в процедурен език от страна на сървъра като plpgsql) ще върне не само на изявлението, но и на цялата транзакция .

Без едновременни записи

Т.е.:Никакви други транзакции няма да се опитват да запишат в същата таблица по едно и също време.

  • Изключете редове, които вече са в таблицата с WHERE NOT EXISTS ... или всяка друга приложима техника:

  • Изберете редове, които не присъстват в друга таблица

  • И не забравяйте да премахнете дубликатите вътре вмъкнатият набор също, което не да бъдат изключени от полу-анти-съединяване WHERE NOT EXISTS ...

Една техника за справяне с двете едновременно би била 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 без ключовата дума ALL сгъва дублиращи се редове в източника. Ако знаете, че няма дубликати или не искате да сгъвате дубликати безшумно, използвайте EXCEPT ALL (или някоя от другите техники). Вижте:

  • Използване на клауза EXCEPT в PostgreSQL

Обикновено, ако целевата таблица е голяма , WHERE NOT EXISTS в комбинация с DISTINCT на източника вероятно ще бъде по-бърз:

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

Ако може да има много измамници, първо си струва да ги сгънете в източника. В противен случай използвайте една подзаявка по-малко.

Свързано:

  • Изберете редове, които не присъстват в друга таблица

С едновременни записи

Използвайте Postgres UPSERT реализация INSERT ... ON CONFLICT ... в Postgres 9.5 или по-късно:

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!

Допълнително четене:

  • Как да използвам RETURNING с ON CONFLICT в PostgreSQL?
  • Как да вмъкна ред, който съдържа външен ключ?

Документация:

  • Ръководството
  • Страницата за записване
  • Уики страницата на Postgres

Референтният отговор на Крейг за UPSERT проблеми:

  • Как да UPSERT (СЛИВАНЕ, ВМЕСВАНЕ ... ПРИ ДУБЛИРАНЕ НА АКТУАЛИЗИРАНЕ) в 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. Как мога да добавя колона, която не позволява нулеви стойности в база данни на Postgresql?

  2. Как да възстановим PostgreSQL дъмп файл в Postgres бази данни?

  3. запазване на обект на python в таблица на postgres с туршия

  4. Команда Postgresql COPY, даваща грешка за отказа на разрешения

  5. Генериране на UUID в оператор Postgres за вмъкване?