Encontrar filas duplicadas en SQL Server


231

Tengo una base de datos de organizaciones de SQL Server, y hay muchas filas duplicadas. Quiero ejecutar una instrucción select para tomar todo esto y la cantidad de engaños, pero también devolver los identificadores asociados con cada organización.

Una declaración como:

SELECT     orgName, COUNT(*) AS dupes  
FROM         organizations  
GROUP BY orgName  
HAVING      (COUNT(*) > 1)

Devolverá algo como

orgName        | dupes  
ABC Corp       | 7  
Foo Federation | 5  
Widget Company | 2 

Pero también me gustaría obtener las identificaciones de ellos. ¿Hay alguna forma de hacer esto? Tal vez como un

orgName        | dupeCount | id  
ABC Corp       | 1         | 34  
ABC Corp       | 2         | 5  
...  
Widget Company | 1         | 10  
Widget Company | 2         | 2  

La razón es que también hay una tabla separada de usuarios que se vinculan con estas organizaciones, y me gustaría unificarlas (por lo tanto, eliminar engaños para que los usuarios se vinculen a la misma organización en lugar de organizaciones engañadas). Pero me gustaría separarme manualmente para no estropear nada, pero aún así necesitaría una declaración que devuelva los ID de todas las organizaciones duplicadas para poder revisar la lista de usuarios.

Respuestas:


313
select o.orgName, oc.dupeCount, o.id
from organizations o
inner join (
    SELECT orgName, COUNT(*) AS dupeCount
    FROM organizations
    GROUP BY orgName
    HAVING COUNT(*) > 1
) oc on o.orgName = oc.orgName

44
¿Hay alguna limitación en esta consulta, por ejemplo, si el número de registros es más de 10 millones?
Steam

3
@Steam Tienes razón: esta respuesta no es eficiente en una base de datos más grande con millones de registros. Prefiere GroupBy / Tener respuesta enviada por Aykut, que puede ser optimizada mejor por la base de datos. Una excepción: sugiero usar Count (0) en lugar de Count (*), para simplificar las cosas.
Mike Christian

1
@ Mike: ¿por qué Count (0) vs Count (*)?
KornMuffin

2
@KornMuffin En retrospectiva, mi comentario en Count () es nulo. Usar una evaluación no nula en Count () es útil solo cuando desea contar resultados no nulos devueltos por una combinación externa. De lo contrario, use Count (*). Una gran explicación se encuentra aquí .
Mike Christian

uso isnull()para columnas anulables en la onsección
Arif Ulusoy

92

Puede ejecutar la siguiente consulta y encontrar los duplicados con max(id)esas filas y eliminarlas.

SELECT orgName, COUNT(*), Max(ID) AS dupes 
FROM organizations 
GROUP BY orgName 
HAVING (COUNT(*) > 1)

Pero tendrá que ejecutar esta consulta varias veces.


Tienes que ejecutarlo exactamente las MAX( COUNT(*) ) - 1veces, lo que aún podría ser factible.
DerMike

1
Hola, ¿hay alguna forma de obtener todos los ID en lugar del ID máximo como para 2? Puedo usar max y min, pero ¿qué pasa con más de 2? @DerMike
Mukherjee

31

Puedes hacerlo así:

SELECT
    o.id, o.orgName, d.intCount
FROM (
     SELECT orgName, COUNT(*) as intCount
     FROM organizations
     GROUP BY orgName
     HAVING COUNT(*) > 1
) AS d
    INNER JOIN organizations o ON o.orgName = d.orgName

Si desea devolver solo los registros que se pueden eliminar (dejando uno de cada uno), puede usar:

SELECT
    id, orgName
FROM (
     SELECT 
         orgName, id,
         ROW_NUMBER() OVER (PARTITION BY orgName ORDER BY id) AS intRow
     FROM organizations
) AS d
WHERE intRow != 1

Editar: SQL Server 2000 no tiene la función ROW_NUMBER (). En cambio, puedes usar:

SELECT
    o.id, o.orgName, d.intCount
FROM (
     SELECT orgName, COUNT(*) as intCount, MIN(id) AS minId
     FROM organizations
     GROUP BY orgName
     HAVING COUNT(*) > 1
) AS d
    INNER JOIN organizations o ON o.orgName = d.orgName
WHERE d.minId != o.id

La primera declaración funciona, pero la segunda no parece funcionar.
xtine

¿SQL Server no parece ser capaz de reconocer row_number ()?
xtine

Ah ... ¿tienes una versión anterior de SQL Server? Creo que se introdujo en SQL Server 2005.
Paul

3
gracias otra vez, cada vez que necesitan hacer esto he llegado hasta aquí y te amo
workabyte

9

La solución marcada como correcta no funcionó para mí, pero encontré esta respuesta que funcionó muy bien: obtener una lista de filas duplicadas en MySql

SELECT n1.* 
FROM myTable n1
INNER JOIN myTable n2 
ON n2.repeatedCol = n1.repeatedCol
WHERE n1.id <> n2.id

Obtendrá muchos engaños en el conjunto de resultados, por lo que también tendrá que lidiar con ellos.
Renan

1
Si la identificación es numérica, la comprobación n1.id > n2.idevitará que cada par aparezca dos veces.
starwed

9

Puedes probar esto, es lo mejor para ti

 WITH CTE AS
    (
    SELECT *,RN=ROW_NUMBER() OVER (PARTITION BY orgName ORDER BY orgName DESC) FROM organizations 
    )
    select * from CTE where RN>1
    go

cualquier forma de obtener toda la identificación en una división de coma o columnas diferentes
Arijit Mukherjee

6

Si desea eliminar duplicados:

WITH CTE AS(
   SELECT orgName,id,
       RN = ROW_NUMBER()OVER(PARTITION BY orgName ORDER BY Id)
   FROM organizations
)
DELETE FROM CTE WHERE RN > 1

6
select * from [Employees]

Para encontrar registros duplicados 1) Usando CTE

with mycte
as
(
select Name,EmailId,ROW_NUMBER() over(partition by Name,EmailId order by id) as Duplicate from [Employees]
)
select * from mycte

2) Usando GroupBy

select Name,EmailId,COUNT(name) as Duplicate from  [Employees] group by Name,EmailId 

Esta es la solución más rápida aquí, al SELECCIONAR datos en filas de 10 m. Gracias
Fandango68

4
Select * from (Select orgName,id,
ROW_NUMBER() OVER(Partition By OrgName ORDER by id DESC) Rownum
From organizations )tbl Where Rownum>1

Por lo tanto, los registros con rowum> 1 serán los registros duplicados en su tabla. 'Partición por' primer grupo por los registros y luego serializarlos dándoles números de serie. Entonces rownum> 1 serán los registros duplicados que podrían eliminarse como tales.


Me gusta este porque le permite agregar fácilmente más columnas en la cláusula de selección interna. Entonces, si desea devolver otras columnas de la tabla 'Organizaciones', no tiene que hacer un 'grupo por' en esas columnas.
Gwasshoppa


2
select a.orgName,b.duplicate, a.id
from organizations a
inner join (
    SELECT orgName, COUNT(*) AS duplicate
    FROM organizations
    GROUP BY orgName
    HAVING COUNT(*) > 1
) b on o.orgName = oc.orgName
group by a.orgName,a.id

1
select orgname, count(*) as dupes, id 
from organizations
where orgname in (
    select orgname
    from organizations
    group by orgname
    having (count(*) > 1)
)
group by orgname, id

1

Tienes varias formas de seleccionar duplicate rows.

para mis soluciones, primero considere esta tabla, por ejemplo

CREATE TABLE #Employee
(
ID          INT,
FIRST_NAME  NVARCHAR(100),
LAST_NAME   NVARCHAR(300)
)

INSERT INTO #Employee VALUES ( 1, 'Ardalan', 'Shahgholi' );
INSERT INTO #Employee VALUES ( 2, 'name1', 'lname1' );
INSERT INTO #Employee VALUES ( 3, 'name2', 'lname2' );
INSERT INTO #Employee VALUES ( 2, 'name1', 'lname1' );
INSERT INTO #Employee VALUES ( 3, 'name2', 'lname2' );
INSERT INTO #Employee VALUES ( 4, 'name3', 'lname3' );

Primera solución

SELECT DISTINCT *
FROM   #Employee;

WITH #DeleteEmployee AS (
                     SELECT ROW_NUMBER()
                            OVER(PARTITION BY ID, First_Name, Last_Name ORDER BY ID) AS
                            RNUM
                     FROM   #Employee
                 )

SELECT *
FROM   #DeleteEmployee
WHERE  RNUM > 1

SELECT DISTINCT *
FROM   #Employee

Solución secundaria: identitycampo de uso

SELECT DISTINCT *
FROM   #Employee;

ALTER TABLE #Employee ADD UNIQ_ID INT IDENTITY(1, 1)

SELECT *
FROM   #Employee
WHERE  UNIQ_ID < (
    SELECT MAX(UNIQ_ID)
    FROM   #Employee a2
    WHERE  #Employee.ID = a2.ID
           AND #Employee.FIRST_NAME = a2.FIRST_NAME
           AND #Employee.LAST_NAME = a2.LAST_NAME
)

ALTER TABLE #Employee DROP COLUMN UNIQ_ID

SELECT DISTINCT *
FROM   #Employee

y al final de toda solución use este comando

DROP TABLE #Employee

0

Creo que sé lo que necesitas, necesitaba mezclar las respuestas y creo que obtuve la solución que quería:

select o.id,o.orgName, oc.dupeCount, oc.id,oc.orgName
from organizations o
inner join (
    SELECT MAX(id) as id, orgName, COUNT(*) AS dupeCount
    FROM organizations
    GROUP BY orgName
    HAVING COUNT(*) > 1
) oc on o.orgName = oc.orgName

tener la identificación máxima le dará la identificación del duplicado y la del original, que es lo que pidió:

id org name , dublicate count (missing out in this case) 
id doublicate org name , doub count (missing out again because does not help in this case)

Lo único triste es que lo saques de esta forma

id , name , dubid , name

espero que todavía ayude


0

Supongamos que tenemos la tabla de la tabla 'Estudiante' con 2 columnas:

  • student_id int
  • student_name varchar

    Records:
    +------------+---------------------+
    | student_id | student_name        |
    +------------+---------------------+
    |        101 | usman               |
    |        101 | usman               |
    |        101 | usman               |
    |        102 | usmanyaqoob         |
    |        103 | muhammadusmanyaqoob |
    |        103 | muhammadusmanyaqoob |
    +------------+---------------------+

Ahora queremos ver registros duplicados. Use esta consulta:

select student_name,student_id ,count(*) c from student group by student_id,student_name having c>1;

+---------------------+------------+---+
| student_name        | student_id | c |
+---------------------+------------+---+
| usman               |        101 | 3 |
| muhammadusmanyaqoob |        103 | 2 |
+---------------------+------------+---+

0

Tengo una mejor opción para obtener los registros duplicados en una tabla

SELECT x.studid, y.stdname, y.dupecount
FROM student AS x INNER JOIN
(SELECT a.stdname, COUNT(*) AS dupecount
FROM student AS a INNER JOIN
studmisc AS b ON a.studid = b.studid
WHERE (a.studid LIKE '2018%') AND (b.studstatus = 4)
GROUP BY a.stdname
HAVING (COUNT(*) > 1)) AS y ON x.stdname = y.stdname INNER JOIN
studmisc AS z ON x.studid = z.studid
WHERE (x.studid LIKE '2018%') AND (z.studstatus = 4)
ORDER BY x.stdname

El resultado de la consulta anterior muestra todos los nombres duplicados con identificadores de estudiante únicos y el número de ocurrencias duplicadas

Haga clic aquí para ver el resultado del sql


0
 /*To get duplicate data in table */

 SELECT COUNT(EmpCode),EmpCode FROM tbl_Employees WHERE Status=1 
  GROUP BY EmpCode HAVING COUNT(EmpCode) > 1

0

Yo uso dos métodos para encontrar filas duplicadas. El primer método es el más famoso usando group by y having. El segundo método está utilizando CTE - Expresión de tabla común .

Como mencionó @RedFilter, esta forma también es correcta. Muchas veces encuentro que el método CTE también es útil para mí.

WITH TempOrg (orgName,RepeatCount)
AS
(
SELECT orgName,ROW_NUMBER() OVER(PARTITION by orgName ORDER BY orgName) 
AS RepeatCount
FROM dbo.organizations
)
select t.*,e.id from organizations   e
inner join TempOrg t on t.orgName= e.orgName
where t.RepeatCount>1

En el ejemplo anterior, recopilamos el resultado al encontrar la repetición usando ROW_NUMBER y PARTITION BY. Luego aplicamos la cláusula where para seleccionar solo las filas que están en el recuento repetido más de 1. Todo el resultado se recopila en la tabla CTE y se une con la tabla Organizaciones.

Fuente: CodoBee


-2

Tratar

SELECT orgName, id, count(*) as dupes
FROM organizations
GROUP BY orgName, id
HAVING count(*) > 1;
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.