Modificar datos · CASE · patrón práctico

UPDATE con CASE: actualizar varias filas con valores distintos

Asigna un valor diferente a cada fila dentro de un solo UPDATE, sin convertir la condición de seguridad en una ocurrencia posterior.

Lectura: 10–12 minIntermediaSQL comprobado
Contenido de esta guía

La idea: una fila puede recibir un valor distinto dentro del mismo UPDATE

Un UPDATE normal suele asignar el mismo valor o la misma fórmula a todas las filas que cumplen WHERE. Pero a veces ya conoces un valor diferente para cada fila: por ejemplo, después de un recuento de inventario quieres dejar el producto 1 con 20 unidades, el 2 con 9 y el 3 con 6.

En ese caso, una expresión CASE puede decidir qué valor recibe cada fila. El modelo mental es: WHERE limita qué filas pueden cambiar; CASE decide el valor nuevo dentro de ese conjunto. Las dos partes son necesarias.

Este patrón resulta útil para lotes pequeños y explícitos. Si los valores nuevos ya están en otra tabla o el lote crece mucho, suele ser más claro usar una tabla de origen y el patrón UPDATE con JOIN / UPDATE FROM.

Patrón general

UPDATE + CASE
UPDATE tabla
SET columna = CASE clave
  WHEN valor_clave_1 THEN nuevo_valor_1
  WHEN valor_clave_2 THEN nuevo_valor_2
  ELSE columna
END
WHERE clave IN (valor_clave_1, valor_clave_2);

La forma simple CASE clave WHEN ... funciona bien cuando comparas la misma columna con varios valores concretos. Si cada rama necesita una condición distinta, puedes usar CASE WHEN condicion THEN valor ... END.

ELSE columna conserva el valor actual cuando ninguna rama coincide, pero no sustituye al WHERE. Mantener ambos hace visible la intención: el WHERE restringe el alcance y el ELSE evita convertir una fila inesperada en NULL si la expresión cambia más adelante.

Ejemplo comprobado: corregir tres existencias

En la base educativa, Ratón tiene 18 unidades, Teclado 7 y Monitor 24 tiene 4. Supón que un recuento físico confirma 20, 9 y 6 unidades respectivamente. Primero conviene revisar las filas objetivo; después puedes ejecutar el cambio dentro de una transacción y comprobar el resultado antes de decidir si confirmarlo.

SQLite · ejecutado y revertido
BEGIN;

SELECT id, nombre, stock
FROM productos
WHERE id IN (1, 2, 3)
ORDER BY id;

UPDATE productos
SET stock = CASE id
  WHEN 1 THEN 20
  WHEN 2 THEN 9
  WHEN 3 THEN 6
  ELSE stock
END
WHERE id IN (1, 2, 3);

SELECT id, nombre, stock
FROM productos
WHERE id IN (1, 2, 3)
ORDER BY id;

ROLLBACK;
Resultado observado antes de ROLLBACK
idnombrestock
1Ratón20
2Teclado9
3Monitor 246

El UPDATE afecta exactamente tres filas. Como el ejemplo termina con ROLLBACK, la base vuelve a 18, 7 y 4 unidades. La transacción permite revisar el estado resultante, pero la seguridad principal sigue estando en una condición que identifica las filas correctas.

CASE simple o CASE buscado

Cuando cada fila se identifica por una clave

Usa la forma simple si todas las ramas comparan la misma expresión:

CASE simple
SET stock = CASE id
  WHEN 1 THEN 20
  WHEN 2 THEN 9
  WHEN 3 THEN 6
  ELSE stock
END

Cuando cada rama tiene una condición diferente

La forma buscada permite condiciones más expresivas. Por ejemplo, podrías aplicar distintos cálculos por nivel de stock:

CASE buscado
UPDATE productos
SET stock = CASE
  WHEN stock = 0 THEN 5
  WHEN stock < 5 THEN stock + 3
  ELSE stock
END
WHERE stock < 5;

En ambos casos, CASE devuelve una expresión de resultado. No es un bucle ni ejecuta varios UPDATE; el motor evalúa la expresión para cada fila dentro del alcance de la sentencia.

Tres controles que evitan cambios masivos

1. Probar primero el mismo WHERE con SELECT

Antes de modificar, ejecuta un SELECT con la misma condición. Si esperas tres filas y aparecen treinta, el problema está en el alcance y todavía estás a tiempo de corregirlo.

2. No confiar solo en ELSE

Un ELSE stock puede dejar sin cambios las filas que no coinciden con ninguna rama, pero un UPDATE sin WHERE sigue evaluando todas las filas de la tabla. Eso aumenta trabajo, complica el razonamiento y puede afectar otras columnas si la sentencia evoluciona.

3. Evitar CASE sin ELSE cuando existe una columna NOT NULL

Si ninguna rama coincide y no existe ELSE, CASE devuelve NULL. En una columna que no acepta nulos, eso puede provocar un error; en una columna que sí los acepta, puede introducir un dato que no pretendías.

Cuándo no conviene un CASE enorme

Un CASE de tres, cinco o diez claves puede ser fácil de auditar. Cientos de ramas ya esconden la relación entre clave y valor dentro de una sentencia difícil de revisar. Cuando los valores nuevos provienen de otro conjunto de datos, suele ser mejor representarlos como filas y relacionarlos con la tabla objetivo.

Según el motor, eso puede expresarse con UPDATE ... FROM, UPDATE ... JOIN, una tabla temporal, una CTE o una estrategia equivalente. La página UPDATE con JOIN / UPDATE FROM explica esas diferencias. No hay una regla universal de rendimiento: la elección depende del tamaño del lote, índices, plan y motor.

Compatibilidad entre PostgreSQL, MySQL, SQL Server y SQLite

El patrón básico es ampliamente portable porque UPDATE ... SET acepta expresiones y CASE es una expresión condicional en estos motores. PostgreSQL permite expresiones en los valores de SET y documenta CASE como expresión condicional; MySQL define los valores de una asignación de UPDATE como expresiones y admite el operador CASE; SQL Server documenta expresamente el uso de CASE dentro de UPDATE; SQLite permite expresiones escalares a la derecha de cada asignación y define ambas formas de CASE.

Lo que sí cambia entre motores es la sintaxis de transacciones, las extensiones de UPDATE y las formas de actualizar a partir de otras tablas. Para este patrón pequeño, la estructura UPDATE ... SET columna = CASE ... END WHERE ... evita depender de esas extensiones.

Comprueba lo aprendido

Intermedia · modificación segura

Cambia dos estados con valores diferentes

En la tabla pedidos, cambia el pedido 102 a 'enviado' y el 105 a 'cancelado' en una sola sentencia. No modifiques ninguna otra fila.

Criterio de éxito: después del UPDATE, la consulta de comprobación devuelve exactamente 102 → enviado y 105 → cancelado.

Qué debes recordar

  • WHERE decide qué filas pueden cambiar; CASE decide qué valor recibe cada una.
  • La forma CASE clave WHEN ... es adecuada para asignar valores explícitos por identificador.
  • ELSE columna conserva el valor actual, pero no reemplaza una condición de alcance precisa.
  • Sin ELSE, una fila que no coincida con ninguna rama recibe NULL.
  • Antes de ejecutar, comprueba el mismo WHERE con SELECT y verifica cuántas filas esperas modificar.
  • Para lotes grandes o valores almacenados en otra tabla, considera UPDATE FROM, UPDATE JOIN o una estrategia equivalente de tu motor.

Conceptos relacionados

Fuentes técnicas consultadas