Условный оператор INSERT INTO в postgres

Я пишу процедуру бронирования для имитации базы данных бронирования авиакомпаний, и я действительно хочу сделать что-то вроде этого:

IF EXISTS (SELECT * FROM LeadCustomer 
    WHERE FirstName = 'John' AND Surname = 'Smith') 
THEN
   INSERT INTO LeadCustomer (Firstname, Surname, BillingAddress, email) 
   VALUES ('John', 'Smith', '6 Brewery close,
            Buxton, Norfolk', '[email protected]');

Но Postgres не поддерживает операторы IF без загрузки расширения PL/pgSQL. Мне было интересно, есть ли способ сделать какой-то эквивалент этого или на этом этапе просто должно быть какое-то взаимодействие с пользователем?


person The General    schedule 29.03.2013    source источник
comment
Почему бы тогда просто не загрузить расширение PL/pgSQL?   -  person Matt Ball    schedule 29.03.2013
comment
@MattBall: работа с установкой postgres на лабораторных компьютерах. Использование этого расширения не входит в спецификацию.   -  person The General    schedule 29.03.2013


Ответы (2)


Эту конкретную команду можно выполнить следующим образом:

insert into LeadCustomer (Firstname, Surname, BillingAddress, email)
select 
    'John', 'Smith', 
    '6 Brewery close, Buxton, Norfolk', '[email protected]'
where not exists (
    select 1 from leadcustomer where firstname = 'John' and surname = 'Smith'
);

Он вставит результат оператора select, а select вернет строку только в том случае, если этот клиент не существует.

person Clodoaldo Neto    schedule 29.03.2013
comment
Я предполагаю, что здесь есть (очень маленькая) гонка? Выполняется подзапрос select, возвращает 0 строк, происходит вставка в другом потоке, а затем происходит вставка LeadCustomer? - person Kevin Burke; 07.08.2015
comment
@Kevin Будет возбуждено исключение первичного ключа, и приложение решит, что делать. - person Clodoaldo Neto; 07.08.2015
comment
Я в замешательстве, в вопросе нигде не упоминаются первичные ключи. Если бы был первичный ключ (имя, фамилия), почему бы вам просто не попробовать сначала вставить? - person Kevin Burke; 07.08.2015
comment
@ Кевин, я бы сначала попробовал вставку. Вопрос только о синтаксисе. - person Clodoaldo Neto; 07.08.2015
comment
Есть ли способ вставить несколько строк, как это? - person Callum Rogers; 12.07.2017
comment
@CallumRogers Несколько или один — это нормально. это зависит от вашего предложения where. - person chuongtv; 21.03.2019
comment
@CallumRogers с несколькими строками не работает - person thepurpleowl; 21.08.2019

Начиная с версии 9.5 включен upsert pgsql, используя INSERT ... ON CONFLICT ОБНОВИТЬ...

Ответ ниже уже не актуален. Пару лет спустя был выпущен Postgres 9.5 с лучшим решением.

В Postgres нет функциональности upsert" без добавления новых функций.
Что? вам нужно будет запустить запрос выбора и посмотреть, есть ли у вас совпадающие строки. Если да, то вставьте его.

Я знаю, что вы не хотите апсерт, но это почти то же самое.

person Trenton Trama    schedule 29.03.2013
comment
это будет продолжать увеличивать автоматически увеличиваемый идентификатор даже при наличии конфликта (при попытке вставки) - person rohanagarwal; 15.09.2017
comment
Проверьте результаты, и условная вставка склонна к условиям гонки: если у вас есть два потока, выполняющих это одновременно, вы можете получить две вставки. - person Charles Duffy; 15.11.2017
comment
@CharlesDuffy не в транзакции (или нет, если она выбрана для обновления) - person Kamil Tomšík; 11.04.2018