UPDATE modifica los valores de filas existentes; DELETE las elimina. Son las instrucciones más peligrosas de SQL: un UPDATE o DELETE sin WHERE afecta a todas las filas de la tabla, y una vez ejecutado en modo autocommit no hay vuelta atrás. La regla de oro es: siempre escribe y verifica el WHERE antes de ejecutar.
En este capítulo cubrimos UPDATE y DELETE con ejemplos, el patrón de verificación previa con SELECT, TRUNCATE como alternativa al DELETE sin WHERE, y los JOINs en UPDATE y DELETE (extensión MySQL).
UPDATE básico
-- Actualizar un solo campo UPDATE productos SET precio = 54.99 WHERE id = 1; -- Actualizar múltiples campos a la vez UPDATE clientes SET ciudad = 'Bilbao', nombre = 'Ana García Pérez' WHERE id = 1; -- Actualizar con expresión (subir el precio un 10%) UPDATE productos SET precio = ROUND(precio * 1.10, 2) WHERE id_categoria = 1; -- Actualizar con la fecha actual UPDATE pedidos SET estado = 'enviado', lastupdate = NOW() WHERE id = 42;
Verificar antes de actualizar
Antes de ejecutar un UPDATE, convierte el WHERE en un SELECT para confirmar qué filas se van a afectar:
-- Primero: ¿qué filas voy a actualizar? SELECT id, nombre, precio FROM productos WHERE id_categoria = 1; -- Si el resultado es correcto, ejecutar el UPDATE: UPDATE productos SET precio = ROUND(precio * 1.10, 2) WHERE id_categoria = 1;
UPDATE con JOIN (MySQL)
-- Aplicar un 5% de descuento a los pedidos de clientes de Madrid UPDATE pedidos p JOIN clientes c ON c.id = p.id_cliente SET p.total = ROUND(p.total * 0.95, 2) WHERE c.ciudad = 'Madrid' AND p.estado = 'pendiente';
DELETE básico
-- Eliminar una fila por ID DELETE FROM clientes WHERE id = 42; -- Eliminar según condición DELETE FROM pedidos WHERE estado = 'cancelado' AND fecha < '2024-01-01'; -- ¡NUNCA hagas esto sin estar absolutamente seguro! -- DELETE FROM productos; ← borra TODOS los productos
DELETE con JOIN (MySQL)
-- Eliminar las líneas de pedido de pedidos cancelados DELETE lp FROM lineas_pedido lp JOIN pedidos p ON p.id = lp.id_pedido WHERE p.estado = 'cancelado'; -- Con múltiples tablas a la vez (MySQL permite borrar de varias tablas en un JOIN): DELETE p, lp FROM pedidos p JOIN lineas_pedido lp ON lp.id_pedido = p.id WHERE p.estado = 'cancelado' AND p.fecha < '2024-01-01';
TRUNCATE: borrar todas las filas rápidamente
-- TRUNCATE elimina todas las filas y resetea el AUTO_INCREMENT -- Es mucho más rápido que DELETE sin WHERE (no guarda log de cada fila) -- NO se puede deshacer con ROLLBACK (en MySQL, TRUNCATE es DDL, no DML) TRUNCATE TABLE pedidos; -- DELETE sin WHERE: más lento, pero se puede deshacer con ROLLBACK BEGIN; DELETE FROM pedidos; ROLLBACK; -- los pedidos vuelven
Soft delete: marcar como eliminado sin borrar
-- Patrón habitual en producción: añadir columna 'deleted_at' ALTER TABLE clientes ADD COLUMN deleted_at DATETIME NULL DEFAULT NULL; -- "Borrar" un cliente (soft delete) UPDATE clientes SET deleted_at = NOW() WHERE id = 42; -- En todas las consultas, filtrar los eliminados: SELECT * FROM clientes WHERE deleted_at IS NULL; -- Ventajas: auditoría, posibilidad de recuperar, integridad referencial
Modo seguro en MySQL
MySQL Workbench activa por defecto el modo seguro (sql_safe_updates), que impide UPDATE y DELETE sin WHERE que incluya una columna indexada. En la CLI se puede activar manualmente para mayor seguridad:
SET sql_safe_updates = 1; -- Ahora UPDATE/DELETE sin WHERE sobre columna indexada fallan con error 1175
