PostgreSQL - вставка данных с дублирующимися уникальными полями

PostgreSQL - вставка данных с дублирующимися уникальными полями

В данной статье мы подробно рассмотрим процесс вставки данных. В том числе, как избежать ошибок при вставке дублирующихся данных. Все операции мы будем производить на тестовой базе PostgreSQL, дамп данной базы вы можете скачать по ссылке: https://www.postgresqltutorial.com/postgresql-sample-database/

Какой самый простой способ вставить данные в таблицу customer? Напомню, что синтаксис будет следующий:

INSERT INTO customer (active, activebool, address_id, create_date, email, first_name, last_name, last_update, store_id) VALUES (1, default, 10, default, 'test2@test.com', 'Andrey', 'Vasilyev', default, 2)

Для вставки нескольких значений, синтаксис будет следующим:

INSERT INTO customer (active, activebool, address_id, create_date, email, first_name, last_name, last_update, store_id) VALUES (1, default, 10, default, 'test2@test.com', 'Andrey', 'Vasilyev', default, 2), (1, default, 11, default, 'test4@test.com', 'Ivan', 'Ivanov', default, 2) returning customer_id;

Заметили в конце фразу "returning customer_id"? Она позволяет после вставки получить в ответ id добавленных записей.

Теперь давайте сделаем следующую очень распространённую вещь - сделаем поле email в этой таблице уникальным:

ALTER TABLE customer ADD CONSTRAINT email_unique UNIQUE (email);

И теперь давайте попробуем вставить уже существующую запись следующим образом:

INSERT INTO customer (active, activebool, address_id, create_date, email, first_name, last_name, last_update, store_id) SELECT active, activebool, address_id, create_date, email, first_name, last_name, last_update, store_id FROM customer WHERE customer_id = 10 returning customer_id

Т.е. данным запросом мы пытаемся вставить customer_id с номером 10. И при выполненгии данного запроса мы получим ошибку:

ERROR:  duplicate key value violates unique constraint "email_unique"

Итак, теперь чтобы нам добавить нового пользователя, нужно выполнить перед инструкцией insert следующий запрос:

SELECT count(1) FROM customer WHERE email = 'test2@test.com'

Т.е. проверим, что пользователя с таким email нет в базе.

Однако, есть гораздо более простой способ сделать это. Попробуем следующий запрос:

INSERT INTO customer (active, activebool, address_id, create_date, email, first_name, last_name, last_update, store_id) VALUES (1, default, 19, default, 'helen.harris@sakilacustomer.org', 'Helen', 'Harris', default, 1) on conflict do nothing

И заметьте, что мы в ответ не получим никакой ошибки, запрос будет выполнен успешно, несмотря на то, что пользователь присутствует в базе.

У этого подхода есть ещё одно преимущество. Вместо того, чтобы просто ничего не делать при обнаружении дубликата, мы можем обновить запись. Например, представим ситуацию, что пользователь Helen сменил место жительства, т.е. переехал в другой город. И при попытке повторной регистрации нам требуется обновить адрес, а также имя и фамилию в случае если они также были изменены. Сделать нам это поможет следующий запрос:

INSERT INTO customer (active, activebool, address_id, create_date, email, first_name, last_name, last_update, store_id) VALUES (1, default, 20, default, 'helen.harris@sakilacustomer.org', 'Helena', 'Harry', default, 1) on conflict (email) do update set first_name = excluded.first_name, last_name = excluded.last_name, address_id = excluded.address_id returning customer_id

Заметим, что в этом запросе мы указали поле email, по которому мы проперяем по дубликаты, указываем действие, которые мы должны совершить (do update). И затем указываем маппинг, по которому мы обновляем поля (first_name = excluded.first_name, last_name = excluded.last_name, address_id = excluded.address_id). По ключевому слову excluded мы обращаемся к нашему новому вставляемому значению, обновляя тем самым значения поля. А фразой "returning customer_id" мы получаем в ответ id клиента.

Популярное

Самые популярные посты

Как быть максимально продуктивным на удалённой работе?
Business

Как быть максимально продуктивным на удалённой работе?

Я запустил собственный бизнес и намеренно сделал всё возможное, чтобы работать из любой точки мира. Иногда я сижу с своём кабинете с большим 27-дюймовым монитором в своей квартире в г. Чебоксары. Иногда я нахожусь в офисе или в каком-нибудь кафе в другом городе.

Привет! Меня зовут Сергей Емельянов и я трудоголик
Business PHP

Привет! Меня зовут Сергей Емельянов и я трудоголик

Я программист. В душе я предприниматель. Я начал зарабатывать деньги с 11 лет, в суровые 90-е годы, сдавая стеклотару в местный магазин и обменивая её на сладости. Я зарабатывал столько, что хватало на разные вкусняшки.

Акция! Профессиональный разработчик CRM за 2000 руб. в час

Выделю время под ваш проект. Знания технологий Vtiger CRM, SuiteCRM, Laravel, Vue.js, Golang, React.js. Предлагаю варианты сотрудничества, которые помогут вам воспользоваться преимуществами внешнего опыта, оптимизировать затраты и снизить риски. Полная прозрачность всех этапов работы и учёт временных затрат. Оплачивайте только рабочие часы разработки после приемки задачи. Экономьте на платежах по его содержанию разработчика в штате. Возможно заключение договора по ИП. С чего начать, чтобы нанять профессионального разработчика на full-time? Просто заполните форму!

Telegram
@sergeyem
Telephone
+4915211100235