MISE À JOUR (2015-08-20):
Il existe maintenant une implémentation officielle pour la gestion des upserts via ON CONFLICT DO UPDATE
(documentation officielle). Au moment de la rédaction de cet article, cette fonctionnalité réside actuellement dans PostgreSQL 9.5 Alpha 2, disponible au téléchargement ici: Répertoires sources de Postgres .
Voici un exemple, en supposant que item_id
soit votre clé primaire:
INSERT INTO my_table
(item_id, price)
VALUES
(123456, 10.99)
ON
CONFLICT (item_id)
DO UPDATE SET
price = EXCLUDED.price
Original Post ...
Voici une implémentation à laquelle je suis arrivé lorsque je souhaitais avoir une visibilité sur la présence ou non d'une insertion ou d'une mise à jour.
La définition de upsert_data
consiste à consolider les valeurs dans une seule ressource, plutôt que de devoir spécifier le prix et l'id_liste deux fois: une fois pour la mise à jour, à nouveau pour l'insertion.
WITH upsert_data AS (
SELECT
'19.99'::numeric(10,2) AS price,
'abcdefg'::character varying AS item_id
),
update_outcome AS (
UPDATE pricing_tbl
SET price = upsert_data.price
FROM upsert_data
WHERE pricing_tbl.item_id = upsert_data.item_id
RETURNING 'update'::text AS action, item_id
),
insert_outcome AS (
INSERT INTO
pricing_tbl
(price, item_id)
SELECT
upsert_data.price AS price,
upsert_data.item_id AS item_id
FROM upsert_data
WHERE NOT EXISTS (SELECT item_id FROM update_outcome LIMIT 1)
RETURNING 'insert'::text AS action, item_id
)
SELECT * FROM update_outcome UNION ALL SELECT * FROM insert_outcome
Si vous n'aimez pas l'utilisation de upsert_data
, voici une autre implémentation:
WITH update_outcome AS (
UPDATE pricing_tbl
SET price = '19.99'
WHERE pricing_tbl.item_id = 'abcdefg'
RETURNING 'update'::text AS action, item_id
),
insert_outcome AS (
INSERT INTO
pricing_tbl
(price, item_id)
SELECT
'19.99' AS price,
'abcdefg' AS item_id
WHERE NOT EXISTS (SELECT item_id FROM update_outcome LIMIT 1)
RETURNING 'insert'::text AS action, item_id
)
SELECT * FROM update_outcome UNION ALL SELECT * FROM insert_outcome