traer solo repetir repetidos registros mostrar evitar eliminar duplicados dejando consulta agrupar sql-server tsql duplicates

sql-server - repetir - sql eliminar registros repetidos dejando solo 1



¿Cómo puedo eliminar filas duplicadas? (30)

Desde el nivel de aplicación (por desgracia). Estoy de acuerdo en que la forma correcta de evitar la duplicación es en el nivel de la base de datos mediante el uso de un índice único, pero en SQL Server 2005, se permite que un índice sea de solo 900 bytes, y mi campo varchar (2048) hace desaparecer.

No sé qué tan bien se desempeñaría, pero creo que podría escribir un disparador para hacer cumplir esto, incluso si no pudiera hacerlo directamente con un índice. Algo como:

-- given a table stories(story_id int not null primary key, story varchar(max) not null) CREATE TRIGGER prevent_plagiarism ON stories after INSERT, UPDATE AS DECLARE @cnt AS INT SELECT @cnt = Count(*) FROM stories INNER JOIN inserted ON ( stories.story = inserted.story AND stories.story_id != inserted.story_id ) IF @cnt > 0 BEGIN RAISERROR(''plagiarism detected'',16,1) ROLLBACK TRANSACTION END

Además, varchar (2048) me suena raro (algunas cosas en la vida son 2048 bytes, pero es bastante raro); ¿Realmente no debería ser varchar (max)?

¿Cuál es la mejor manera de eliminar filas duplicadas de una tabla de SQL Server bastante grande (es decir, más de 300,000 filas)?

Las filas, por supuesto, no serán duplicados perfectos debido a la existencia del campo de identidad RowID .

Mi mesa

RowID int not null identity(1,1) primary key, Col1 varchar(20) not null, Col2 varchar(2048) not null, Col3 tinyint not null


  1. Crear nueva tabla en blanco con la misma estructura.

  2. Ejecutar consulta como esta

    INSERT INTO tc_category1 SELECT * FROM tc_category GROUP BY category_id, application_id HAVING count(*) > 1

  3. Entonces ejecuta esta consulta

    INSERT INTO tc_category1 SELECT * FROM tc_category GROUP BY category_id, application_id HAVING count(*) = 1


Al utilizar la siguiente consulta, podemos eliminar registros duplicados basados ​​en la columna única o en la columna múltiple. La siguiente consulta se borra en base a dos columnas. nombre de la tabla es: testing y nombres de columna empno,empname

DELETE FROM testing WHERE empno not IN (SELECT empno FROM (SELECT empno, ROW_NUMBER() OVER (PARTITION BY empno ORDER BY empno) AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1) or empname not in (select empname from (select empname,row_number() over(PARTITION BY empno ORDER BY empno) AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)


Aquí hay otro buen artículo sobre la eliminación de duplicados .

Explica por qué es difícil: " SQL se basa en el álgebra relacional, y los duplicados no pueden ocurrir en el álgebra relacional, porque no se permiten duplicados en un conjunto " .

La solución de la tabla temporal, y dos ejemplos mysql.

En el futuro, va a evitarlo a nivel de base de datos o desde una perspectiva de aplicación. Sugeriría el nivel de la base de datos porque su base de datos debería ser responsable de mantener la integridad referencial, los desarrolladores solo causarán problemas;)


Esta consulta mostró muy buen rendimiento para mí:

DELETE tbl FROM MyTable tbl WHERE EXISTS ( SELECT * FROM MyTable tbl2 WHERE tbl2.SameValue = tbl.SameValue AND tbl.IdUniqueValue < tbl2.IdUniqueValue )

eliminó 1M filas en poco más de 30 segundos de una tabla de 2M (50% de duplicados)




Hay un buen artículo sobre la eliminación de duplicados en el sitio de soporte de Microsoft. Es bastante conservador: te hacen hacer todo en pasos separados, pero debería funcionar bien contra mesas grandes.

En el pasado, utilicé auto-inscripciones para hacer esto, aunque probablemente podría ser un pretexto con una cláusula HAVING:

DELETE dupes FROM MyTable dupes, MyTable fullTable WHERE dupes.dupField = fullTable.dupField AND dupes.secondDupField = fullTable.secondDupField AND dupes.uniqueField > fullTable.uniqueField


La otra forma es crear una nueva tabla con los mismos campos y con un índice único . Luego mueva todos los datos de la tabla antigua a la tabla nueva . Automáticamente se ignora el SERVIDOR SQL (también hay una opción sobre qué hacer si habrá un valor duplicado: ignorar, interrumpir o sth) valores duplicados. Así que tenemos la misma tabla sin filas duplicadas. Si no desea un Índice Único, después de la transferencia de datos, puede soltarlo .

Especialmente para tablas más grandes , puede usar DTS (paquete SSIS para importar / exportar datos) para transferir todos los datos rápidamente a su nueva tabla indexada de forma única. Para 7 millones de filas toma solo unos minutos.


La siguiente consulta es útil para eliminar filas duplicadas. La tabla en este ejemplo tiene ID como una columna de identidad y las columnas que tienen datos duplicados son Column1 , Column2 y Column3 .

DELETE FROM TableName WHERE ID NOT IN (SELECT MAX(ID) FROM TableName GROUP BY Column1, Column2, Column3 /*Even if ID is not null-able SQL Server treats MAX(ID) as potentially nullable. Because of semantics of NOT IN (NULL) including the clause below can simplify the plan*/ HAVING MAX(ID) IS NOT NULL)

La siguiente secuencia de comandos muestra el uso de GROUP BY , HAVING , ORDER BY en una consulta y devuelve los resultados con una columna duplicada y su recuento.

SELECT YourColumnName, COUNT(*) TotalCount FROM YourTableName GROUP BY YourColumnName HAVING COUNT(*) > 1 ORDER BY COUNT(*) DESC


Mencionaría este enfoque, así como puede ser útil, y funciona en todos los servidores SQL: a menudo hay solo uno, dos duplicados, y se conocen las identificaciones y el número de duplicados. En este caso:

SET ROWCOUNT 1 -- or set to number of rows to be deleted delete from myTable where RowId = DuplicatedID SET ROWCOUNT 0


Oh, por supuesto. Utilice una tabla de temperatura. Si desea una declaración única, que no funciona muy bien y que "funcione", puede ir con:

DELETE FROM MyTable WHERE NOT RowID IN (SELECT (SELECT TOP 1 RowID FROM MyTable mt2 WHERE mt2.Col1 = mt.Col1 AND mt2.Col2 = mt.Col2 AND mt2.Col3 = mt.Col3) FROM MyTable mt)

Básicamente, para cada fila en la tabla, la sub-selección encuentra el RowID superior de todas las filas que son exactamente como la fila en consideración. Así que terminas con una lista de RowID que representan las filas "no duplicadas" originales.


Otra forma posible de hacer esto es

; --Ensure that any immediately preceding statement is terminated with a semicolon above WITH cte AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3 ORDER BY ( SELECT 0)) RN FROM #MyTable) DELETE FROM cte WHERE RN > 1;

Estoy usando ORDER BY (SELECT 0) arriba, ya que es arbitrario qué fila conservar en caso de un empate.

Para conservar el último en el orden de RowID , por ejemplo, puede utilizar ORDER BY RowID DESC

Planes de ejecución

El plan de ejecución para esto es a menudo más simple y más eficiente que el de la respuesta aceptada, ya que no requiere la unión automática.

Esto no es siempre el caso, sin embargo. Un lugar donde la solución GROUP BY podría preferirse es en situaciones en las que un agregado de hash se elegiría con preferencia a un agregado de flujo.

La solución ROW_NUMBER siempre dará casi el mismo plan, mientras que la estrategia GROUP BY es más flexible.

Factores que podrían favorecer el enfoque de hash agregado serían

  • Ningún índice útil en las columnas de partición
  • relativamente menos grupos con relativamente más duplicados en cada grupo

En las versiones extremas de este segundo caso (si hay muy pocos grupos con muchos duplicados en cada uno), también se podría considerar simplemente insertar las filas para mantenerlas en una nueva tabla, TRUNCATE enviar el original y volver a copiarlo para minimizar el registro comparado con la eliminación Una proporción muy alta de las filas.


Otra solución fácil se puede encontrar en el enlace pegado http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server . Este es fácil de entender y parece ser efectivo para la mayoría de los problemas similares. Sin embargo, es para SQL Server, pero el concepto utilizado es más que aceptable.

Aquí están las partes relevantes de la página enlazada:

Considere estos datos:

EMPLOYEE_ID ATTENDANCE_DATE A001 2011-01-01 A001 2011-01-01 A002 2011-01-01 A002 2011-01-01 A002 2011-01-01 A003 2011-01-01

Entonces, ¿cómo podemos eliminar esos datos duplicados?

Primero, inserte una columna de identidad en esa tabla usando el siguiente código:

ALTER TABLE dbo.ATTENDANCE ADD AUTOID INT IDENTITY(1,1)

Usa el siguiente código para resolverlo:

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _ FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE)


Pensé que compartiría mi solución ya que funciona en circunstancias especiales. En mi caso, la tabla con valores duplicados no tenía una clave externa (porque los valores se duplicaron desde otra db).

begin transaction -- create temp table with identical structure as source table Select * Into #temp From tableName Where 1 = 2 -- insert distinct values into temp insert into #temp select distinct * from tableName -- delete from source delete from tableName -- insert into source from temp insert into tableName select * from #temp rollback transaction -- if this works, change rollback to commit and execute again to keep you changes!!

PD: cuando trabajo en cosas como esta, siempre uso una transacción, esto no solo garantiza que todo se ejecute como un todo, sino que también me permite realizar pruebas sin arriesgar nada. Pero, por supuesto, deberías hacer una copia de seguridad de todos modos para estar seguro ...


Preferiría CTE para eliminar filas duplicadas de la tabla del servidor SQL

Recomiendo encarecidamente seguir este artículo: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

manteniendo original

WITH CTE AS ( SELECT *,ROW_NUMBER() OVER (PARTITION BY col1,col2,col3 ORDER BY col1,col2,col3) AS RN FROM MyTable ) DELETE FROM CTE WHERE RN<>1

sin guardar original

WITH CTE AS (SELECT *,R=RANK() OVER (ORDER BY col1,col2,col3) FROM MyTable)   DELETE CTE WHERE R IN (SELECT R FROM CTE GROUP BY R HAVING COUNT(*)>1)


Prefiero la subconsulta / tener cuenta (*)> 1 solución a la combinación interna porque me resultó más fácil de leer y fue muy fácil convertirla en una instrucción SELECT para verificar lo que se eliminaría antes de ejecutarlo.

--DELETE FROM table1 --WHERE id IN ( SELECT MIN(id) FROM table1 GROUP BY col1, col2, col3 -- could add a WHERE clause here to further filter HAVING count(*) > 1 --)


Rápido y sucio para eliminar filas duplicadas exactas (para tablas pequeñas):

select distinct * into t2 from t1; delete from t1; insert into t1 select * from t2; drop table t2;


Si desea obtener una vista previa de las filas que está a punto de eliminar y mantener el control sobre cuál de las filas duplicadas debe mantener. Consulte http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/

with MYCTE as ( SELECT ROW_NUMBER() OVER ( PARTITION BY DuplicateKey1 ,DuplicateKey2 -- optional ORDER BY CreatedAt -- the first row among duplicates will be kept, other rows will be removed ) RN FROM MyTable ) DELETE FROM MYCTE WHERE RN > 1


Suponiendo que no haya nulos, se agrupan por las columnas únicas y SELECT el MINI MIN (or MAX) RowId como la fila a mantener. Luego, simplemente borre todo lo que no tenía una identificación de fila:

DELETE FROM MyTable LEFT OUTER JOIN ( SELECT MIN(RowId) as RowId, Col1, Col2, Col3 FROM MyTable GROUP BY Col1, Col2, Col3 ) as KeepRows ON MyTable.RowId = KeepRows.RowId WHERE KeepRows.RowId IS NULL

En caso de que tenga un GUID en lugar de un entero, puede reemplazar

MIN(RowId)

con

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))


Tenía una tabla donde necesitaba preservar filas no duplicadas. No estoy seguro de la velocidad o la eficiencia.

DELETE FROM myTable WHERE RowID IN ( SELECT MIN(RowID) AS IDNo FROM myTable GROUP BY Col1, Col2, Col3 HAVING COUNT(*) = 2 )


Utilizando CTE. La idea es unirse en una o más columnas que forman un registro duplicado y luego eliminar lo que quieras:

;with cte as ( select min(PrimaryKey) as PrimaryKey UniqueColumn1, UniqueColumn2 from dbo.DuplicatesTable group by UniqueColumn1, UniqueColumn1 having count(*) > 1 ) delete d from dbo.DuplicatesTable d inner join cte on d.PrimaryKey > cte.PrimaryKey and d.UniqueColumn1 = cte.UniqueColumn1 and d.UniqueColumn2 = cte.UniqueColumn2;


Utilizar esta

WITH tblTemp as ( SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name) As RowNumber,* FROM <table_name> ) DELETE FROM tblTemp where RowNumber >1


Para buscar filas duplicadas:

SELECT name, email, COUNT(*) FROM users GROUP BY name, email HAVING COUNT(*) > 1

Para eliminar las filas duplicadas:

DELETE users WHERE rowid NOT IN (SELECT MIN(rowid) FROM users GROUP BY name, email);


CREATE TABLE car(Id int identity(1,1), PersonId int, CarId int) INSERT INTO car(PersonId,CarId) VALUES(1,2),(1,3),(1,2),(2,4) --SELECT * FROM car ;WITH CTE as( SELECT ROW_NUMBER() over (PARTITION BY personid,carid order by personid,carid) as rn,Id,PersonID,CarId from car) DELETE FROM car where Id in(SELECT Id FROM CTE WHERE rn>1)


DELETE FROM table_name T1 WHERE rowid > ( SELECT min(rowid) FROM table_name T2 WHERE T1.column_name = T2.column_name );


DELETE FROM MyTable WHERE NOT EXISTS ( SELECT min(RowID) FROM Mytable WHERE (SELECT RowID FROM Mytable GROUP BY Col1, Col2, Col3 )) );


DELETE LU FROM (SELECT *, Row_number() OVER ( partition BY col1, col1, col3 ORDER BY rowid DESC) [Row] FROM mytable) LU WHERE [row] > 1


SELECT DISTINCT * INTO tempdb.dbo.tmpTable FROM myTable TRUNCATE TABLE myTable INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable DROP TABLE tempdb.dbo.tmpTable


delete t1 from table t1, table t2 where t1.columnA = t2.columnA and t1.rowid>t2.rowid

Postgres:

delete from table t1 using table t2 where t1.columnA = t2.columnA and t1.rowid > t2.rowid