Поиск повторяющихся строк в SQL Server

У меня есть база данных организаций 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  

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


person xtine    schedule 21.01.2010    source источник


Ответы (15)


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

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

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

person Aykut Akıncı    schedule 21.01.2010
comment
Вы должны запустить его ровно MAX( COUNT(*) ) - 1 раз, что все еще возможно. - person DerMike; 09.08.2016
comment
привет, есть ли у них любой способ получить все идентификаторы вместо максимального идентификатора, например, для 2, я могу использовать max и min, но как насчет более 2? @DerMike - person Arijit Mukherjee; 05.12.2016

Сделать это можно так:

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
person Paul    schedule 21.01.2010
comment
Первый оператор работает, но второй, похоже, не работает. - person xtine; 21.01.2010
comment
SQL Server не может распознать row_number ()? - person xtine; 21.01.2010
comment
Ах ... у вас есть более старая версия SQL Server? Я считаю, что это было введено в SQL Server 2005. - person Paul; 22.01.2010
comment
Еще раз спасибо, каждый раз, когда мне нужно это сделать, я прихожу сюда и ЛЮБЛЮ ТЕБЯ - person workabyte; 08.03.2014

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

 WITH CTE AS
    (
    SELECT *,RN=ROW_NUMBER() OVER (PARTITION BY orgName ORDER BY orgName DESC) FROM organizations 
    )
    select * from CTE where RN>1
    go
person code save    schedule 07.11.2013
comment
любой способ получить все идентификаторы в разделенных запятыми или в разных столбцах - person Arijit Mukherjee; 05.12.2016

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

SELECT n1.* 
FROM myTable n1
INNER JOIN myTable n2 
ON n2.repeatedCol = n1.repeatedCol
WHERE n1.id <> n2.id
person ecairol    schedule 20.05.2013
comment
Вы получите много дубликатов в наборе результатов, так что вам тоже придется иметь дело с ними. - person Geeky Guy; 10.05.2016
comment
Если идентификатор числовой, проверка n1.id > n2.id предотвратит повторное отображение каждой пары. - person starwed; 07.06.2016

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

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

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 
person Debendra Dash    schedule 18.11.2016
comment
Это самое быстрое решение при выборе данных из более чем 10 млн строк. Спасибо - person Fandango68; 18.01.2018

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 будет дублирующимися записями, которые могут быть удалены как таковые.

person Mike Clark    schedule 10.03.2015
comment
Мне нравится этот, потому что он позволяет легко добавлять дополнительные столбцы во внутреннем предложении выбора. Поэтому, если вы хотите вернуть другие столбцы из таблицы «Организации», вам не нужно выполнять группировку по этим столбцам. - person Gwasshoppa; 22.04.2015

select column_name, count(column_name)
from table_name
group by column_name
having count (column_name) > 1;

Источник: https://stackoverflow.com/a/59242/1465252

person iCrazybest    schedule 17.03.2015
comment
Это будет работать только с таблицами с одним столбцом. Что, скорее всего, бесполезно - person Zach Smith; 13.10.2016

У вас есть несколько способов выбора 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
person Ardalan Shahgholi    schedule 07.11.2013

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

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

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

person Arthur Kielbasa    schedule 01.10.2014

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

  • 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 |
+---------------------+------------+---+
person Usman Yaqoob    schedule 09.02.2018

У меня есть лучший вариант получить повторяющиеся записи в таблице

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

person SoftIdea    schedule 25.06.2018

Я использую два метода для поиска повторяющихся строк. 1-й метод является наиболее известным с использованием группы по и имея. Второй метод использует CTE - Общее табличное выражение.

Как упоминал @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.

person Ishrar    schedule 05.05.2020

Пытаться

SELECT orgName, id, count(*) as dupes
FROM organizations
GROUP BY orgName, id
HAVING count(*) > 1;
person ryan    schedule 22.01.2014

person    schedule
comment
есть ли какие-либо ограничения в этом запросе, например, если количество записей превышает 10 миллионов? - person Steam; 07.02.2014
comment
@Steam Вы правы: этот ответ неэффективен в большой базе данных с миллионами записей. Предпочитайте ответ GroupBy / Have, представленный Aykut, который может быть лучше оптимизирован базой данных. Одно исключение: для упрощения я предлагаю использовать Count (0) вместо Count (*). - person Mike Christian; 23.09.2014
comment
@Mike - почему Count (0) vs Count (*)? - person KornMuffin; 14.09.2015
comment
@KornMuffin Оглядываясь назад, мой комментарий к Count () недействителен. Использование ненулевой оценки в Count () полезно только тогда, когда вы хотите подсчитать ненулевые результаты, возвращаемые внешним соединением. В противном случае используйте Count (*). Прекрасное объяснение можно найти здесь. - person Mike Christian; 13.10.2015
comment
используйте isnull() для столбцов, допускающих значение NULL, в разделе on - person Arif Ulusoy; 09.03.2017