AGGIORNAMENTO (20-08-2015):
Ora esiste un'implementazione ufficiale per la gestione degli UPS tramite l'uso di ON CONFLICT DO UPDATE
(documentazione ufficiale). Al momento della stesura di questo documento, questa funzione risiede attualmente in PostgreSQL 9.5 Alpha 2, che è disponibile per il download qui: directory sorgente di Postgres .
Ecco un esempio, supponendo che item_id
sia la chiave primaria:
INSERT INTO my_table
(item_id, price)
VALUES
(123456, 10.99)
ON
CONFLICT (item_id)
DO UPDATE SET
price = EXCLUDED.price
Posta originale ...
Ecco un'implementazione a cui sono arrivato quando desideravo ottenere visibilità sull'inserimento o l'aggiornamento.
La definizione di upsert_data
è consolidare i valori in una singola risorsa, anziché dover specificare il prezzo e item_id due volte: una volta per l'aggiornamento, di nuovo per l'inserimento.
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
Se non ti piace l'uso di upsert_data
, ecco un'implementazione alternativa:
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