ACTUALIZACIÓN (2015-08-20):
Ahora hay una implementación oficial para el manejo de upserts mediante el uso de ON CONFLICT DO UPDATE
(documentación oficial). Al momento de escribir este artículo, esta característica actualmente reside en PostgreSQL 9.5 Alpha 2, que está disponible para descargar aquí: directorios fuente de Postgres .
Aquí hay un ejemplo, suponiendo que item_id
sea su clave principal:
INSERT INTO my_table
(item_id, price)
VALUES
(123456, 10.99)
ON
CONFLICT (item_id)
DO UPDATE SET
price = EXCLUDED.price
Publicación original ...
Aquí hay una implementación a la que llegué cuando deseaba obtener visibilidad sobre si se produjo una inserción o actualización.
La definición de upsert_data
es consolidar los valores en un solo recurso, en lugar de tener que especificar el precio y item_id dos veces: una vez para la actualización, otra vez para la inserción.
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 no le gusta el uso de upsert_data
, aquí hay una implementación 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