Actualizar datos: la sentencia UPDATE
Los datos que se añaden no siempre siguen siendo correctos: la gente se cambia de apellido, en los pagos aparecen erratas y hay que recalcular precios. Para corregir una fila sin borrarla se usa la sentencia UPDATE.
Estructura general de una consulta con UPDATE
UPDATE nombre_tabla
SET campo_tabla = valor [, ...]
[WHERE condicion_seleccion];- [ ]parte opcional
- ...se puede repetir
- nombre_tabla
- La tabla en la que se modifican los registros.
- campo_tabla
La columna a la que se asigna un valor nuevo. Puede haber varios pares campo_tabla = valor separados por comas.
- valor
El valor nuevo: un número, una cadena, una expresión como price * 1.1 o NULL.
- condicion_seleccion
Qué filas modificar. Sin WHERE se modifican todas las filas de la tabla.
Opcional
Por ejemplo, Andie (Andie Quincey) se ha cambiado el apellido: ahora es Andie Anthony.
MySQL 8.4UPDATE FamilyMembers SET member_name = 'Andie Anthony' WHERE member_name = 'Andie Quincey';
| member_id | status | member_name | birthday |
|---|---|---|---|
| 1 | father | Headley Quincey | 1960-05-13T00:00:00.000Z |
| 2 | mother | Flavia Quincey | 1963-02-16T00:00:00.000Z |
| 3 | son | 1983-06-05T00:00:00.000Z | |
| 4 | daughter | Lela Quincey | 1985-06-07T00:00:00.000Z |
| 5 4 filas más | daughter | Annie Quincey | 1988-04-10T00:00:00.000Z |
Modificar varias columnas
Para modificar varias columnas a la vez, enumera después de SET los pares campo_tabla = valor separados por comas. Por ejemplo, Andie compró 4 envases de leche a 25 cada uno, pero en el pago con identificador 3 se registraron por error 5 a 20. Corrijamos las dos columnas con una sola consulta:
MySQL 8.4UPDATE Payments SET amount = 4, unit_price = 25 WHERE payment_id = 3;
| payment_id | date | family_member | good | amount | unit_price |
|---|---|---|---|---|---|
| 1 | 2005-02-12T00:00:00.000Z | 1 | 1 | 1 | 2000 |
| 2 | 2005-03-23T00:00:00.000Z | 2 | 1 | 1 | 2100 |
| 3 | 2005-05-14T00:00:00.000Z | 3 | 4 | ||
| 4 | 2005-07-22T00:00:00.000Z | 4 | 5 | 1 | 350 |
| 5 24 filas más | 2005-07-26T00:00:00.000Z | 4 | 7 | 2 | 150 |
Todas las columnas enumeradas cambian en las mismas filas: las que cumplen la condición de WHERE.
Valores calculados
El valor nuevo se puede calcular a partir del anterior; por ejemplo, para duplicar todos los precios:
MySQL 8.4UPDATE Payments SET unit_price = unit_price * 2;
En la expresión también puedes usar otras columnas de la misma fila, siempre que sus tipos sean compatibles. Por ejemplo, vamos a registrar el pago con identificador 3 como una sola unidad: en unit_price quedará el importe de toda la compra y en amount, el valor 1.
MySQL 8.4UPDATE Payments SET unit_price = unit_price * amount, amount = 1 WHERE payment_id = 3;
En un UPDATE sobre una sola tabla, las asignaciones de SET se ejecutan de izquierda a derecha, y la siguiente expresión ya ve el valor nuevo de la columna. Si cambias el orden de las asignaciones, unit_price se multiplicará por el 1 que ya se ha escrito en amount y no cambiará:
MySQL 8.4UPDATE Payments SET amount = 1, unit_price = unit_price * amount WHERE payment_id = 3;
Por eso, la columna que interviene en el cálculo de otras debes modificarla la última.
Todas las expresiones de SET se calculan con los valores que tenía la fila antes del cambio, así que el orden de las asignaciones da igual. Esta consulta dará el mismo resultado:
MySQL 8.4UPDATE Payments SET amount = 1, unit_price = unit_price * amount WHERE payment_id = 3;
Actualizar según los datos de otra tabla
A veces las filas que hay que actualizar se eligen según los datos de otra tabla. Por ejemplo, resulta que en todos los pagos de caviar el precio registrado es la mitad del real. La forma más sencilla es usar una subconsulta en WHERE:
MySQL 8.4UPDATE Payments SET unit_price = unit_price * 2 WHERE good IN ( SELECT good_id FROM Goods WHERE good_name LIKE '%caviar%' );
Lo mismo se puede conseguir combinando las tablas con JOIN directamente en la consulta UPDATE:
UPDATE nombre_tabla_1
JOIN nombre_tabla_2 ON condicion_combinacion
SET nombre_tabla_1.campo_tabla = valor [, ...]
[WHERE condicion_seleccion];- [ ]parte opcional
- ...se puede repetir
- nombre_tabla_1
- La tabla en la que se modifican los registros.
- nombre_tabla_2
La tabla que se combina y según cuyos datos se seleccionan las filas y se calculan los valores nuevos.
- condicion_combinacion
Cómo se relacionan las filas de las dos tablas, por ejemplo nombre_tabla_1.campo = nombre_tabla_2.campo.
- condicion_seleccion
Qué filas modificar. En la condición se pueden comprobar columnas de ambas tablas.
Opcional
MySQL 8.4UPDATE Payments JOIN Goods ON Payments.good = Goods.good_id SET Payments.unit_price = Payments.unit_price * 2 WHERE Goods.good_name LIKE '%caviar%';
Lo mismo se puede conseguir enumerando las tablas adicionales después de FROM:
UPDATE nombre_tabla_1
SET campo_tabla = valor [, ...]
FROM nombre_tabla_2
WHERE condicion_combinacion
[AND condicion_seleccion];- [ ]parte opcional
- ...se puede repetir
- nombre_tabla_1
La tabla en la que se modifican los registros. No hace falta repetirla después de FROM.
- campo_tabla
Una columna de la tabla nombre_tabla_1. Delante de ella no se indica el nombre de la tabla.
- nombre_tabla_2
Una tabla adicional según cuyos datos se seleccionan las filas y se calculan los valores nuevos.
- condicion_combinacion
Cómo se relacionan las filas de las dos tablas, por ejemplo nombre_tabla_1.campo = nombre_tabla_2.campo.
- condicion_seleccion
Una condición adicional: cuáles de las filas relacionadas modificar.
Opcional
MySQL 8.4UPDATE Payments SET unit_price = unit_price * 2 FROM Goods WHERE Payments.good = Goods.good_id AND Goods.good_name LIKE '%caviar%';
En una subconsulta no se puede leer la misma tabla que está modificando UPDATE. Por ejemplo, así no podrás duplicar el precio de los pagos que están por debajo de la media:
MySQL 8.4UPDATE Payments SET unit_price = unit_price * 2 WHERE unit_price < (SELECT AVG(unit_price) FROM Payments);
La consulta terminará con un error:
MySQL 8.4ERROR 1093 (HY000): You can't specify target table 'Payments' for update in FROM clause
Puedes sortear esta limitación envolviendo la subconsulta en otro SELECT. Así, primero se calcula el precio medio y se guarda en una tabla temporal, y la actualización lee ya de ella:
MySQL 8.4UPDATE Payments SET unit_price = unit_price * 2 WHERE unit_price < ( SELECT avg_price FROM (SELECT AVG(unit_price) AS avg_price FROM Payments) AS stats );
Errores típicos
Olvidar el WHERE
Una consulta sin condición modificará todas las filas de la tabla. Comprueba primero la condición con una consulta SELECT y solo después ponla en el UPDATE.
AND en lugar de coma en SET
La consulta de abajo no modifica dos columnas: todo lo que queda a la derecha del primer = se considera una única expresión lógica.
MySQL 8.4UPDATE Payments SET amount = 4 AND unit_price = 25 WHERE payment_id = 3;
La consulta se ejecutará sin errores y guardará en amount el resultado de esa expresión (0 o 1), mientras que unit_price no cambiará.
La consulta terminará con un error:
MySQL 8.4ERROR: argument of AND must be type boolean, not type integer
Para modificar las dos columnas, las asignaciones se separan con una coma. Así SET sabe dónde termina una y empieza la siguiente:
MySQL 8.4UPDATE Payments SET amount = 4, unit_price = 25 WHERE payment_id = 3;
Comparar con NULL usando =
La condición WHERE campo = NULL no se cumple para ninguna fila, así que la consulta no modificará nada. Para comprobar si un valor está vacío, usa IS NULL.
Ponte a prueba
Algunos usuarios de la tabla Users no tienen indicada la fecha de confirmación del correo: la columna email_verified_at es NULL. ¿Cuántas filas modificará esta consulta?
MySQL 8.4UPDATE Users SET email_verified_at = '2024-01-01' WHERE email_verified_at = NULL;