794 votes

Insertion, sur mise à jour dupliquée dans PostgreSQL ?

Il y a plusieurs mois, j'ai appris d'une réponse sur Stack Overflow comment effectuer plusieurs mises à jour à la fois dans MySQL en utilisant la syntaxe suivante :

INSERT INTO table (id, field, field2) VALUES (1, A, X), (2, B, Y), (3, C, Z)
ON DUPLICATE KEY UPDATE field=VALUES(Col1), field2=VALUES(Col2);

Je suis maintenant passé à PostgreSQL et apparemment ce n'est pas correct. Il se réfère à toutes les tables correctes, je suppose donc qu'il s'agit de l'utilisation de mots-clés différents, mais je ne sais pas où dans la documentation de PostgreSQL cela est couvert.

Pour clarifier, je veux insérer plusieurs choses et, si elles existent déjà, les mettre à jour.

46 votes

Quiconque trouve cette question devrait lire l'article de Depesz "Pourquoi l'upsert est si compliqué ?" . Il explique très bien le problème et les solutions possibles.

8 votes

UPSERT sera ajouté dans Postgres 9.5 : wiki.postgresql.org/wiki/

5 votes

@tommed - cela a été fait : stackoverflow.com/a/34639631/4418

3voto

Joey Adams Points 13049

Edita: Cela ne fonctionne pas comme prévu. Contrairement à la réponse acceptée, cela produit des violations de clé unique lorsque deux processus appellent de manière répétée upsert_foo en même temps.

Eurêka ! J'ai trouvé un moyen de le faire en une seule requête : utiliser UPDATE ... RETURNING pour vérifier si des lignes ont été affectées :

CREATE TABLE foo (k INT PRIMARY KEY, v TEXT);

CREATE FUNCTION update_foo(k INT, v TEXT)
RETURNS SETOF INT AS $$
    UPDATE foo SET v = $2 WHERE k = $1 RETURNING $1
$$ LANGUAGE sql;

CREATE FUNCTION upsert_foo(k INT, v TEXT)
RETURNS VOID AS $$
    INSERT INTO foo
        SELECT $1, $2
        WHERE NOT EXISTS (SELECT update_foo($1, $2))
$$ LANGUAGE sql;

En UPDATE doit être effectuée dans une procédure distincte car, malheureusement, il s'agit d'une erreur de syntaxe :

... WHERE NOT EXISTS (UPDATE ...)

Maintenant, cela fonctionne comme souhaité :

SELECT upsert_foo(1, 'hi');
SELECT upsert_foo(1, 'bye');
SELECT upsert_foo(3, 'hi');
SELECT upsert_foo(3, 'bye');

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X