J'ai un tableau tag
avec 2 colonnes: id
(uuid) et name
(text). Je veux maintenant insérer une nouvelle balise dans la table, mais si la balise existe déjà, je veux simplement obtenir le id
de l'enregistrement existant.
J'ai supposé que je pouvais simplement l'utiliser ON CONFLICT DO NOTHING
en combinaison avec RETURNING "id"
:
INSERT INTO
"tag" ("name")
VALUES( 'foo' )
ON CONFLICT DO NOTHING
RETURNING "id";
Mais cela renvoie un jeu de résultats vide, si la balise avec le nom "foo" existe déjà.
J'ai ensuite modifié la requête pour utiliser une DO UPDATE
clause noop :
INSERT INTO
"tag" ("name")
VALUES( 'foo' )
ON CONFLICT ("name") DO UPDATE SET "name" = 'foo'
RETURNING "id";
Cela fonctionne comme prévu, mais c'est un peu déroutant, car je ne fais que définir le nom sur la valeur déjà existante.
Est-ce la façon de régler ce problème ou y a-t-il une approche plus simple qui me manque?
postgresql
upsert
postgresql-9.5
Der Hochstapler
la source
la source
returning excluded.id
?ERROR: missing FROM-clause entry for table "excluded"
lors de l'utilisationDO NOTHING
.Réponses:
Cela fonctionnera (pour autant que j'ai testé) dans les 3 cas, si les valeurs à insérer sont toutes nouvelles ou toutes déjà dans le tableau ou un mélange:
Il y a probablement d'autres façons de le faire, peut-être sans utiliser la nouvelle
ON CONFLICT
syntaxe.la source
Aucune idée de la façon dont cela fonctionnera, mais juste comme une autre option à essayer, voici la même chose à l'ancienne (sans
ON CONFLICT
):Autrement dit, insérez uniquement les noms [uniques] introuvables dans le
tag
tableau et renvoyez les ID; combinez cela avec les ID des noms qui existent danstag
la sortie finale. Vous pouvez également lancername
dans la sortie, comme suggéré par ypercubeᵀᴹ , afin de savoir quel ID correspond à quel nom.la source
SELECT .. FROM ins UNION ALL SELECT ... FROM val JOIN tag ... ;