Ejecutar un DELETE con respaldo lógico y reversión controlada

Una corrección requiere retirar movimientos de inventario identificados y anteriores a una fecha. Además de comprobar el filtro, necesitamos conservar una copia recuperable si la eliminación llega a confirmarse.

Qué necesitamos distinguir

Un respaldo lógico copia las filas seleccionadas dentro de otra tabla; no sustituye un respaldo completo de la base. El identificador de lote agrupa las filas copiadas por una misma ejecución.

La vista previa, el respaldo y la eliminación deben referirse al mismo conjunto. Utilizaremos un identificador de lote para conservar las filas en una tabla permanente y confirmaremos el respaldo y el DELETE dentro de una sola transacción, una unidad que se confirma o revierte completa.

Consulta

/*
    Antes de ejecutar:
        Revisa la base activa, los nombres de objetos, los parámetros y los permisos.
        Adapta el ejemplo a tu modelo y pruébalo primero en un ambiente controlado.
    Los cambios se revierten de forma predeterminada.
    Mantén @ConfirmarCambios = 0 hasta validar el alcance.
*/

SET NOCOUNT ON;
GO
-- Consulta
DECLARE @FechaLimite DATETIME2(0) = '2026-01-01T00:00:00';
DECLARE @Referencia NVARCHAR(100) = N'Carga temporal';
DECLARE @MaximoFilas INT = 100;
DECLARE @ConfirmarCambios BIT = 0;
DECLARE @IdLote UNIQUEIDENTIFIER = NEWID();

IF OBJECT_ID(N'dbo.RespaldoMovimientoInventario', N'U') IS NULL
    THROW 50010, N'No existe la tabla de respaldo requerida.', 1;

SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRANSACTION;

    INSERT INTO dbo.RespaldoMovimientoInventario
    (
        IdLote, FechaRespaldo, IdMovimiento, IdProducto,
        TipoMovimiento, Cantidad, FechaMovimiento, Referencia
    )
    SELECT
        @IdLote, SYSDATETIME(), mi.IdMovimiento, mi.IdProducto,
        mi.TipoMovimiento, mi.Cantidad, mi.FechaMovimiento, mi.Referencia
    FROM dbo.MovimientoInventario AS mi WITH (UPDLOCK, HOLDLOCK)
    WHERE mi.FechaMovimiento < @FechaLimite
      AND mi.Referencia = @Referencia;

    DECLARE @FilasObjetivo INT = @@ROWCOUNT;

    IF @FilasObjetivo > @MaximoFilas
        THROW 50011, N'El DELETE supera el máximo de filas esperado.', 1;

    SELECT
        r.IdLote,
        r.IdMovimiento,
        r.IdProducto,
        r.TipoMovimiento,
        r.Cantidad,
        r.FechaMovimiento,
        r.Referencia
    FROM dbo.RespaldoMovimientoInventario AS r
    WHERE r.IdLote = @IdLote
    ORDER BY r.IdMovimiento;

    DELETE mi
    OUTPUT
        @IdLote,
        deleted.IdMovimiento,
        deleted.IdProducto,
        deleted.FechaMovimiento
    FROM dbo.MovimientoInventario AS mi
    INNER JOIN dbo.RespaldoMovimientoInventario AS r
        ON r.IdLote = @IdLote
       AND r.IdMovimiento = mi.IdMovimiento;

    IF @@ROWCOUNT <> @FilasObjetivo
        THROW 50012, N'Cambió el número de filas durante el DELETE.', 1;

    IF @ConfirmarCambios = 1
        COMMIT TRANSACTION;
    ELSE
        ROLLBACK TRANSACTION;
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0
        ROLLBACK TRANSACTION;

    THROW;
END CATCH;
GO

Parámetros o permisos

La tabla dbo.RespaldoMovimientoInventario debe existir antes de la corrección, con las columnas mostradas y una llave que impida repetir IdLote e IdMovimiento. Debe formar parte de la política autorizada de conservación, acceso y eliminación de respaldos. Adapta filtros y límite. El ejemplo revierte por defecto. Requiere lectura y eliminación en la tabla original, inserción y lectura en la tabla de respaldo, y visibilidad de metadatos para la comprobación inicial.

Cómo leer el resultado

La primera consulta muestra el conjunto que ya fue copiado bajo un lote único, antes de ejecutar el DELETE. La eliminación se une a ese mismo lote y no vuelve a calcular el filtro. Las comprobaciones detienen la operación si cambia la cantidad. Si se ejecuta ROLLBACK, tanto la eliminación como el respaldo de ese intento se revierten y las filas originales permanecen. Si se confirma, el respaldo y la eliminación persisten juntos. La consulta final permite revisar la copia antes de tomar esa decisión. Una tabla temporal o una variable de tabla sirve para inspeccionar, pero no conserva un respaldo después de cerrar la sesión. OUTPUT por sí solo tampoco es una estrategia durable.

Qué conclusión sí permite obtener

Permite demostrar qué filas integran el lote, conservarlas en una tabla permanente y comprobar que el mismo número fue eliminado dentro de una transacción.

Qué conclusión todavía no permite obtener

No garantiza una restauración completa si existen tablas relacionadas, triggers o efectos externos. Una FK puede impedir el borrado y una cascada puede afectar filas no incluidas en este respaldo.

Siguiente comprobación razonable

Prueba una restauración por IdLote en un ambiente controlado. Revisa relaciones, triggers, auditoría, retención y permisos antes de confirmar una eliminación en producción.

Índice del recorrido

Desarrollo y exploración

22 artículos de Desarrollo y exploración
  1. 01Buscar una tabla o vista por nombre
  2. 02Buscar una columna en toda la base
  3. 03Buscar texto dentro de procedimientos, vistas y funciones
  4. 04Consultar dependencias de un objeto
  5. 05Listar relaciones y llaves foráneas
  6. 06Consultar llaves primarias, restricciones únicas e índices
  7. 07Listar columnas con tipo, longitud, nulabilidad y valor predeterminado
  8. 08Encontrar triggers y sus tablas asociadas
  9. 09Encontrar objetos modificados recientemente
  10. 10Obtener conteos aproximados de todas las tablas
  11. 11Medir el espacio utilizado por cada tabla
  12. 12Revisar columnas IDENTITY y su valor actual
  13. 13Detectar registros duplicados por una clave de negocio
  14. 14Detectar registros huérfanos
  15. 15Comparar dos conjuntos de datos
  16. 16Validar conversiones antes de modificar una columna
  17. 17Ejecutar un UPDATE con validación y reversión controlada
  18. 18Ejecutar un DELETE con respaldo lógico y reversión controlada
  19. 19Comparar la estructura de dos bases de datos
  20. 20Describir el resultado de una consulta o procedimiento
  21. 21Encontrar tablas sin llave primaria
  22. 22Buscar un valor en columnas seleccionadas