Поиск дублирующихся строк в SQL Server


231

У меня есть база данных организаций SQL Server, и есть много повторяющихся строк. Я хочу выполнить оператор select, чтобы получить все эти данные и количество дубликатов, а также вернуть идентификаторы, связанные с каждой организацией.

Заявление как:

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

Вернет что-то вроде

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

Но я также хотел бы получить их удостоверения личности. Есть какой-либо способ сделать это? Может быть, как

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

Причина в том, что существует также отдельная таблица пользователей, которые ссылаются на эти организации, и я хотел бы объединить их (поэтому удалите дубликаты, чтобы пользователи ссылались на одну и ту же организацию, а не на двойные организации). Но я бы хотел расставить детали вручную, чтобы ничего не напортачить, но мне все равно нужно заявление, возвращающее идентификаторы всех двойных организаций, чтобы я мог просмотреть список пользователей.

Ответы:


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

4
Существуют ли какие-либо ограничения в этом запросе, например, если количество записей превышает 10 миллионов?
Steam

3
@ Steam Вы правы: этот ответ неэффективен в большой базе данных с миллионами записей. Предпочитайте GroupBy / Имея ответ, представленный Aykut, который может быть лучше оптимизирован базой данных. Единственное исключение: я предлагаю использовать Count (0) вместо Count (*), чтобы упростить вещи.
Майк Кристиан

1
@ Майк - почему Count (0) против Count (*)?
KornMuffin

2
@KornMuffin В ретроспективе мой комментарий к Count () является недействительным. Использование ненулевой оценки в Count () полезно, только если вы хотите подсчитать ненулевые результаты, возвращаемые внешним объединением. В противном случае используйте Count (*). Отличное объяснение находится здесь .
Майк Кристиан

использовать isnull()для обнуляемых столбцов на onсекции
Ариф Улусой

92

Вы можете выполнить следующий запрос, найти дубликаты max(id)и удалить эти строки.

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

Но вам придется выполнить этот запрос несколько раз.


Вы должны запустить его ровно MAX( COUNT(*) ) - 1раз, что все еще возможно.
DerMike

1
Привет, есть ли какой-нибудь способ получить все идентификаторы вместо максимального идентификатора, как для 2, я могу использовать max и min, но как насчет более 2? @DerMike
Арижит Мукерджи

31

Вы можете сделать это так:

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

Если вы хотите вернуть только те записи, которые можно удалить (оставив одну из каждой), вы можете использовать:

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

Изменить: SQL Server 2000 не имеет функции ROW_NUMBER (). Вместо этого вы можете использовать:

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

Первое утверждение работает, но второе, похоже, не работает.
xtine

Кажется, SQL Server не может распознать row_number ()?
xtine

Ах ... у вас есть более старая версия SQL Server? Я считаю, что это было введено в SQL Server 2005.
Пол

3
Еще раз спасибо, каждый раз, когда мне нужно сделать это, я попадаю сюда и ЛЮБЛЮ ТЕБЯ
workabyte

9

Решение, помеченное как правильное, не сработало для меня, но я нашел ответ, который работал просто замечательно: получить список повторяющихся строк в MySql

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

В наборе результатов вы получите много дупликов, так что с ними вам тоже придется иметь дело.
Ренан

1
Если идентификатор числовой, проверка n1.id > n2.idне позволит каждой паре появиться дважды.
Starwed

9

Вы можете попробовать это, это лучше для вас

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

любой способ получить все идентификаторы в разделенных запятыми или разных столбцах
Arijit Mukherjee

6

Если вы хотите удалить дубликаты:

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]

Для поиска дубликатов записи 1) Использование 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) Используя GroupBy

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

Это самое быстрое решение здесь, когда ВЫБИРАЕТ данные на 10м строк, то есть. Спасибо
Fandango68

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

Таким образом, записи с rowum> 1 будут дублировать записи в вашей таблице. «Разделить» сначала группу по записям, а затем сериализовать их, дав им серийные номера. Таким образом, rownum> 1 будет дублировать записи, которые могут быть удалены как таковые.


Мне нравится этот, потому что он позволяет вам легко добавлять больше столбцов во внутреннем предложении select. Поэтому, если вы хотите вернуть другие столбцы из таблицы «Организации», вам не нужно выполнять группирование по этим столбцам.
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

У вас есть несколько способов выбора duplicate rows.

для моих решений, сначала рассмотрим эту таблицу, например,

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' );

Первое решение:

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

Второстепенное решение: используйте identityполе

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

и конец всего решения использовать эту команду

DROP TABLE #Employee

0

я думаю, что знаю, что вам нужно, мне нужно было смешать ответы, и я думаю, что я получил решение, которое он хотел:

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

наличие максимального идентификатора даст вам идентификатор дубликата и тот из оригинала, о котором он просил:

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)

единственная грустная вещь, которую вы получите это положить в этой форме

id , name , dubid , name

надеюсь, это все еще помогает


0

Предположим, у нас есть таблица «Студент» с двумя столбцами:

  • student_id int
  • student_name varchar

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

Теперь мы хотим увидеть повторяющиеся записи. Используйте этот запрос:

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

Я получил лучший вариант, чтобы получить дубликаты записей в таблице

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

В результате вышеприведенного запроса отображаются все дубликаты имен с уникальными идентификаторами учеников и количеством повторений.

Нажмите здесь, чтобы увидеть результат 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

Я использую два метода, чтобы найти повторяющиеся строки. 1-й метод является самым известным, использующим группу и имеющую. 2-й метод использует CTE - Common Table Expression .

Как упомянуто @RedFilter, этот путь также верен. Много раз я считаю, что метод CTE также полезен для меня.

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

В приведенном выше примере мы собрали результат, найдя повторение, используя ROW_NUMBER и PARTITION BY. Затем мы применили предложение where, чтобы выбрать только те строки, количество повторений которых больше 1. Все результаты собраны в таблице CTE и объединены с таблицей Organizations.

Источник: CodoBee


-2

Пытаться

SELECT orgName, id, count(*) as dupes
FROM organizations
GROUP BY orgName, id
HAVING count(*) > 1;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.