Ir al contenido
wannacode

Upsert: insertar o cambiar

En resumen: Un upsert inserta una fila o cambia la que ya existe con ON CONFLICT … DO UPDATE cuando se rompe una columna única; DO NOTHING se salta el conflicto.

Problema

El cliente vuelve

Georgi Petrov se mudó a Sofía. Pide sin iniciar sesión, y el formulario envía su nombre, su correo y su ciudad. El sitio web intenta guardarlo como cliente nuevo:

SQLbase de datos: tienda

Su correo ya está en la base de datos, y es único. El sitio web tiene que decidir: ¿cliente nuevo o existente? Podría comprobarlo primero con un SELECT y luego elegir entre INSERT y UPDATE. Pero son dos sentencias, y entre ellas otro visitante podría guardar el mismo correo.

La idea

ON CONFLICT … DO UPDATE

ON CONFLICT le dice a INSERT qué hacer si la fila rompe una columna única. Con DO UPDATE cambia la fila que ya está en la tabla:

SQLbase de datos: tienda

Las dos filas siguen caminos distintos. Georgi está: su fila conserva el número 2 y la fecha de registro de 2025, y solo cambia la ciudad. Vesela no está: se inserta como cliente 21.

excluded es la fila que la sentencia intentó insertar. excluded.city es la ciudad de VALUES, y city sin nada delante es el valor anterior de la tabla.

Esto se llama upsert, de «update» e «insert».

Más precisamente, para curiosos

En PostgreSQL la sentencia es la misma: ON CONFLICT (email) DO UPDATE SET city = EXCLUDED.city. MySQL tiene su propia forma: INSERT … ON DUPLICATE KEY UPDATE. SQL Server y Oracle usan MERGE, una orden más general que compara dos tablas y decide para cada fila: insertar, cambiar o borrar. PostgreSQL tiene MERGE desde la versión 15. SQLite no tiene MERGE.

Pruébalo

Una dirección nueva

Elena Dimitrova (elena.d@example.com) se mudó a Varna. El formulario envía su nombre, su correo, la ciudad Varna y la fecha de hoy, 2026-10-25. Guárdala de modo que solo cambie la ciudad. Su fecha de registro sigue siendo la anterior.

SQLbase de datos: tienda

La idea

Mercancía del proveedor

Por la mañana llega una entrega: 30 banitsas, 40 pepinos y un producto nuevo, el ayran. El proveedor usa los números de producto de la tienda, y el ayran ya tiene el número 26 en el catálogo. Los productos conocidos deben recibir más existencias, y el nuevo debe aparecer:

SQLbase de datos: tienda

El conflicto está en id, la clave primaria. Para la banitsa y los pepinos, products.stock + excluded.stock suma las existencias entregadas a las anteriores. Su fecha added_at se queda como estaba, porque no está en SET. El ayran no está, así que se inserta con todas sus columnas.

Aquí stock lleva products. delante, porque la expresión tiene dos existencias: la de la tabla y la de la entrega.

Pruébalo

Más en el carrito

Georgi añade 2 paquetes de mantequilla (producto 9, 3,20 €) a su pedido nuevo 57. Si ya está, la cantidad debe subir, y si no está, debe añadirse una fila.

SQLbase de datos: tienda

Míralo

DO NOTHING

A veces ante un conflicto no debe cambiar nada. De una feria llega una lista de personas que quieren ser clientes. A quien ya es cliente se le salta:

SQLbase de datos: tienda

Maria se queda como estaba, con la ciudad Sofía. Vesela es una clienta nueva. Sin ON CONFLICT toda la sentencia se habría detenido en Maria, y Vesela no habría entrado.

Más precisamente, para curiosos

SQLite también tiene una forma más antigua propia: INSERT OR IGNORE hace lo mismo que DO NOTHING.

SQLbase de datos: tienda

INSERT OR REPLACE parece un upsert, pero no lo es. Ante un conflicto borra la fila anterior e inserta una nueva. Teodora recibe un número nuevo y una fecha de registro nueva:

SQLbase de datos: tienda

En el caso de Georgi el borrado ni siquiera pasa, porque sus pedidos apuntan a la fila anterior:

SQLbase de datos: tienda

Así que para un upsert usa ON CONFLICT … DO UPDATE. Cambia solo las columnas de SET.

Ejercicio

La entrega

El proveedor envía la entrega como una tabla delivery: número de producto, nombre, categoría, precio y cantidad. Para la lección la tabla ya está en la base de datos. Ejecuta el SELECT inicial para verla.

Guarda la entrega en products. A los productos conocidos se les suma la cantidad entregada a sus existencias y se les pone el precio del proveedor. Los nuevos se insertan con la fecha 2026-10-25.

La entrega en products:

SQLbase de datos: tienda

Test

Ponte a prueba

1. ¿Qué es excluded en ON CONFLICT … DO UPDATE?
2. ¿Cuándo entra en juego ON CONFLICT (email)?
3. ¿Por qué ON CONFLICT (city) no funciona en la tienda?
4. ¿Qué diferencia hay en SQLite entre ON CONFLICT DO UPDATE e INSERT OR REPLACE?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·