UPDATE: modificar únicamente las filas previstas
Actualizar datos parece sencillo hasta que una condición afecta más filas de las esperadas. La parte esencial de un UPDATE no es la asignación, sino demostrar antes cuáles filas cambiarán y comprobar después el resultado.
La idea
UPDATE modifica una o varias columnas en las filas que cumplen WHERE. Si omitimos el filtro, todas las filas de la tabla quedan dentro del alcance.
Sintaxis
UPDATE dbo.Tabla
SET
Columna1 = NuevoValor,
Columna2 = OtraExpresion
WHERE Condicion;
Ejemplo: revisar antes de actualizar
Queremos aumentar 5% el precio de los productos activos de una categoría. Primero observamos el estado actual y calculamos el nuevo valor:
DECLARE @IdCategoria SMALLINT = 1;
DECLARE @Factor DECIMAL(6, 4) = 1.05;
SELECT
p.IdProducto,
p.Nombre,
p.Precio AS PrecioActual,
ROUND(p.Precio * @Factor, 2) AS PrecioNuevo
FROM dbo.Producto AS p
WHERE p.IdCategoria = @IdCategoria
AND p.Activo = 1;
Las primeras líneas crean variables con DECLARE, construcción explicada en la ficha sobre variables.
Después reutilizamos exactamente la misma condición:
UPDATE p
SET
p.Precio = ROUND(p.Precio * @Factor, 2),
p.FechaActualizacion = SYSDATETIME()
FROM dbo.Producto AS p
WHERE p.IdCategoria = @IdCategoria
AND p.Activo = 1;
SELECT @@ROWCOUNT AS FilasActualizadas;
@@ROWCOUNT debe consultarse inmediatamente después del UPDATE, porque otra instrucción puede cambiar su valor.
Actualizar mediante una unión
Cuando el nuevo valor depende de otra tabla podemos utilizar UPDATE ... FROM:
UPDATE p
SET p.Activo = 0
FROM dbo.Producto AS p
INNER JOIN dbo.Categoria AS c
ON c.IdCategoria = p.IdCategoria
WHERE c.Nombre = N'Almacenamiento'
AND p.Existencia = 0;
La unión debe producir una relación inequívoca para cada fila que se actualizará. Si una fila del destino coincide con varias filas de origen, el resultado elegido puede no ser determinista.
Validar con una transacción
En una corrección manual podemos mantener la decisión de confirmar separada de la ejecución:
BEGIN TRANSACTION;
UPDATE dbo.Producto
SET Activo = 0
WHERE IdProducto = 6;
SELECT
IdProducto,
Nombre,
Activo
FROM dbo.Producto
WHERE IdProducto = 6;
-- Sustituir por COMMIT solo después de validar el resultado.
ROLLBACK;
Una transacción abierta conserva bloqueos y utiliza recursos. No debe dejarse esperando indefinidamente mientras se realiza la revisión.
Qué conviene comprobar
Además del número de filas, revisamos los valores anteriores, los nuevos, las restricciones y los efectos indirectos de triggers. También confirmamos que el filtro utilice tipos compatibles y que no dependa de una comparación ambigua con NULL.
En operaciones repetibles conviene evitar actualizaciones innecesarias, por ejemplo agregando una condición que descarte filas cuyo valor ya sea el esperado.
Relacionado con
WHERE: define el alcance del cambio.CASE: asigna valores distintos según la fila.- Transacciones: permiten confirmar o revertir una modificación.
OUTPUT: puede devolver valores anteriores y posteriores.