2013-04-20 9 views
6

Я хочу написать один оператор SQL Postgres, который говорит, что пользователь ищет цвет с X и яркостью Y. Если этот пользователь существует, верните все данные его строки. Если нет, создайте новую строку и передайте дополнительную информацию. Две отдельные заявления будут делать что-то вроде этого:Создать Postgres Получить или создать SQL-запрос

Select (color, brightness, size, age) FROM mytable WHERE color = 'X' AND brightness= 'Y'; 

Если ничего не возвращает, а затем выполнить следующее:

INSERT INTO mytable (color, brightness, size, age) VALUES (X, Y, big, old); 

Есть ли способ, чтобы объединить их в одном запросе ??

+0

В связи с расширением предложения 'RETURNING' postgresql на операторах INSERT я изначально надеялся, что можно комбинировать вставку с выбором в одном выражении с помощью объединения, но я попробовал, и, к сожалению, чтение и запись на самом деле невозможно смешивать сюда. – didierc

ответ

15

В СУБД SQL, то выберите тест-вставка подход является ошибкой: ничто не мешает другой процессу от вставки «недостающей» строки между вашим select и insert заявлением. Сделайте это вместо того, чтобы:

insert into mytable (color, brightness, size, age) 
select (color, brightness, size, age) from mytable 
where not exists (
    select 1 from 
    from mytable 
    where color = 'X' and brightness = 'Y' 
); 
SELECT (color, brightness, size, age) 
FROM mytable 
WHERE color = 'X' AND brightness= 'Y'; 

Вы должны быть в состоянии передать весь этот текст в качестве одного «запроса» в СУБД. Возможно, вы захотите рассмотреть возможность внесения его в хранимую процедуру.

+0

Связано с этим ответом и полезно для лучшего понимания: http://stackoverflow.com/a/13342031/399726 – BenjaminGolder

+0

Не могу понять, как этот ответ собрал так много голосов, содержащих синтаксическую ошибку. Нет опции 'insert ... where ...' для INSERT в Postgres. Вероятно, вы имели в виду «вставлять в mytable (цвет, яркость, размер, возраст) SELECT« X »,« Y », 1.2, 3.4, где не существует ...'. – greatvovan

4
with sel as (
    select color, brightness, size, age 
    from mytable 
    where color = 'X' and brightness = 'Y' 
), ins as (
    insert into mytable (color, brightness, size, age) 
    select 'X', 'Y', 6.2, 40 
    where not exists (
     select 1 from sel 
    ) 
    returning color, brightness, size, age 
) 
select color, brightness, size, age 
from ins 
union 
select color, brightness, size, age 
from sel 
2

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

INSERT INTO mytable (color, brightness, size, age) 
VALUES ('X', 'Y', 'big', 'old') 
ON CONFLICT (color) DO NOTHING; 

(если у вас есть уникальный индекс на color).

Docs является Гиром: https://www.postgresql.org/docs/9.5/static/sql-insert.html

+0

Это не отвечает на вопрос, который запрашивает, как * получить * или * создать * строку. – Druska

1

Добавление моего решения здесь. Это немного отличается от решений @Clodoaldo Neto и @ astef.

WITH ins AS (
    INSERT INTO mytable (color, brightness, size, age) 
    VALUES ('X', 'Y', 'big', 'old') 
    ON CONFLICT (color) DO NOTHING 
    RETURNING * 
) 
SELECT * FROM ins 
UNION 
SELECT * FROM mytable 
    WHERE color = 'X'; 

Я нашел решение astef в неадекватной для моих целей: она не выполняет «получить» часть «получить или создать»! Если значение уже существует, ничего не произойдет.

Объединение в конце инструкции гарантирует, что если значение не было вставлено (поскольку оно уже существовало), мы все равно извлекаем это значение из таблицы.

+0

Я нашел проблему с вышесказанным: если есть конфликт, счетчик последовательных идентификаторов вашей таблицы будет увеличиваться при каждом выполнении запроса. Это не идеально. –

Смежные вопросы