Eliminar duplicados conservando la fila correcta
Defina la identidad del duplicado y la fila ganadora, revise ROW_NUMBER y evite que vuelvan los duplicados después de limpiar.
Lo difícil de eliminar duplicados no es escribir DELETE. Es definir qué representa la misma entidad, qué información debe sobrevivir y cómo mantener referencias válidas. Dos filas con el mismo correo no necesariamente son el mismo cliente. La identidad numérica más alta tampoco es automáticamente el registro más fiable.
Definir igualdad y supervivencia
Exprese la clave duplicada como regla de negocio. Incluya cliente o sistema de origen cuando corresponda. Aclare mayúsculas, acentos, espacios y valores ausentes. Las comparaciones siguen la intercalación. Agrupar NULL puede ser incorrecto si significa identidad desconocida y no identidad compartida.
Elija una regla determinista. En el ejercicio, TenantId y ExternalKey forman la clave; gana la fila observada más recientemente y RowId deshace empates de fecha. Ese último criterio único evita que distintas ejecuciones seleccionen supervivientes diferentes.
Los ExternalKey ausentes quedan excluidos deliberadamente. Cada identidad desconocida permanece independiente hasta otra conciliación. Es una política posible, no una interpretación universal de NULL.
CREATE TABLE #CustomerStage
(RowId int PRIMARY KEY, TenantId int NOT NULL,
ExternalKey varchar(20) NULL, SeenAt datetime2(0) NOT NULL);
INSERT #CustomerStage VALUES
(1,1,'A','2020-01-01'),(2,1,'A','2020-02-01'),
(3,2,'A','2020-01-01'),(4,1,NULL,'2020-01-01'),
(5,1,NULL,'2020-02-01');
;WITH ranked AS
( SELECT *, ROW_NUMBER() OVER
(PARTITION BY TenantId, ExternalKey
ORDER BY SeenAt DESC, RowId DESC) AS rn
FROM #CustomerStage WHERE ExternalKey IS NOT NULL )
SELECT * FROM ranked WHERE rn > 1 ORDER BY RowId;
La víctima esperada es RowId 1. La fila 2 es más nueva para cliente 1 y clave A. La fila 3 pertenece a otro cliente, y 4 y 5 tienen identidad desconocida. Valide esos resultados con el responsable del negocio antes de modificar datos reales.
Controlar la ejecución
El siguiente ejercicio afecta únicamente a la tabla temporal y revierte la eliminación. OUTPUT captura las filas retiradas realmente. Tras rollback, los datos originales siguen intactos. En producción, valide primero regla, volumen, recuperación y concurrencia de escritura.
BEGIN TRAN;
;WITH ranked AS
( SELECT *, ROW_NUMBER() OVER
(PARTITION BY TenantId, ExternalKey
ORDER BY SeenAt DESC, RowId DESC) AS rn
FROM #CustomerStage WHERE ExternalKey IS NOT NULL )
DELETE FROM ranked
OUTPUT deleted.RowId, deleted.TenantId, deleted.ExternalKey
WHERE rn > 1;
ROLLBACK;
Una vista previa de hace horas no garantiza la selección posterior. Pueden llegar filas y cambiar fechas. Use una ventana controlada o aislamiento deliberado que cubra selección, migración de referencias, eliminación y protección de unicidad. Una gran transacción serializable puede bloquear considerablemente; no es una opción gratuita.
Antes de borrar padres, inventaríe claves externas y relaciones no declaradas. Si hijos referencian identidades duplicadas, construya un mapa víctima-superviviente y reasigne según reglas de negocio. Los hijos pueden entonces colisionar en sus propias claves únicas. Resuelva ese conflicto explícitamente; desactivar restricciones solo lo oculta.
Preservar información y evitar recurrencia
La fila nueva puede tener dirección vacía mientras la anterior conserva una dirección verificada. Elegir simplemente una fila perdería información. Consolide atributos con precedencias documentadas y conserve procedencia cuando sea necesaria. El superviviente puede ser un registro combinado, no una fila original sin cambios.
Retenga el mapa auditable y suficientes datos eliminados durante el periodo de recuperación acordado. Una copia de seguridad es indispensable, pero puede resultar incómoda para recuperar algunas relaciones después de otras escrituras legítimas. El registro de recuperación debe identificar claves originales y transformación, con protección adecuada de datos personales.
Después imponga la unicidad real mediante restricción o índice único filtrado coherente con las claves desconocidas. Corrija también la carrera de importación o falta de idempotencia que creó duplicados. Revise cantidades por cliente, atributos supervivientes, referencias y repetición del importador problemático. Incluya empates exactos de fecha y registros incompletos en las pruebas. El éxito elimina solo duplicados confirmados, mantiene información valiosa y rechaza el siguiente duplicado inmediatamente.
Referencias técnicas: Microsoft Learn: ROW_NUMBER · Microsoft Learn: Unique indexes.