У меня есть таблица tag
с 2 столбцами: id
(UUID) и name
(текст). Теперь я хочу вставить новый тег в таблицу, но если тег уже существует, я хочу просто получить id
существующую запись.
Я предположил, что я мог бы просто использовать ON CONFLICT DO NOTHING
в сочетании с RETURNING "id"
:
INSERT INTO
"tag" ("name")
VALUES( 'foo' )
ON CONFLICT DO NOTHING
RETURNING "id";
Но это возвращает пустой набор результатов, если тег с именем «foo» уже существует.
Затем я изменил запрос, чтобы использовать предложение noop DO UPDATE
:
INSERT INTO
"tag" ("name")
VALUES( 'foo' )
ON CONFLICT ("name") DO UPDATE SET "name" = 'foo'
RETURNING "id";
Это работает как задумано, но это несколько сбивает с толку, потому что я просто устанавливаю имя на уже существующее значение.
Это способ решить эту проблему или я упускаю более простой подход?
postgresql
upsert
postgresql-9.5
Der Hochstapler
источник
источник
returning excluded.id
?ERROR: missing FROM-clause entry for table "excluded"
при использованииDO NOTHING
.Ответы:
Это будет работать (насколько я тестировал) во всех 3 случаях, если все подлежащие вставке значения являются новыми или все уже находятся в таблице или в смеси:
Возможно, есть и другие способы сделать это, возможно, без использования нового
ON CONFLICT
синтаксиса.источник
Понятия не имею, как это будет работать, но просто как еще один вариант, здесь все делается по-старому (без
ON CONFLICT
):То есть вставьте только [уникальные] имена, не найденные в
tag
таблице, и верните идентификаторы; объедините это с идентификаторами имен, которые существуют вtag
, для окончательного вывода. Вы также можете добавитьname
в вывод, как предлагает ypercubeᵀᴹ , чтобы вы знали, какой идентификатор соответствует какому имени.источник
SELECT .. FROM ins UNION ALL SELECT ... FROM val JOIN tag ... ;