Поиск повторяющихся значений в таблице SQL


1936

Дубликаты с одним полем легко найти:

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

Так что если у нас есть стол

ID   NAME   EMAIL
1    John   asd@asd.com
2    Sam    asd@asd.com
3    Tom    asd@asd.com
4    Bob    bob@asd.com
5    Tom    asd@asd.com

Этот запрос даст нам Джон, Сэм, Том, Том, потому что они все одинаковы email.

Тем не менее, я хочу получить дубликаты с тем же email и name .

То есть я хочу получить «Том», «Том».

Причина, по которой мне это нужно: я допустил ошибку и позволил вставить дубликаты nameи emailзначения. Теперь мне нужно удалить / изменить дубликаты, поэтому мне нужно сначала найти их.


28
Я не думаю, что это позволит вам выбрать имя в вашем первом примере, поскольку он не входит в составную функцию. «Каково количество совпадающих адресов электронной почты и их имени» - это хитрая логика ...
sXe

3
Обнаружено, что это не работает с сервером MSSQL из-за nameполя в SELECT.
Э. ван Путтен

мне нужен идентификатор записей с дублированным адресом электронной почты
Маркос Паоло

Ответы:


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

Просто сгруппируйте по обоим столбцам.

Примечание: более старый стандарт ANSI должен иметь все неагрегированные столбцы в GROUP BY, но это изменилось с идеей «функциональной зависимости» :

В теории реляционных баз данных функциональная зависимость - это ограничение между двумя наборами атрибутов в отношении из базы данных. Другими словами, функциональная зависимость - это ограничение, которое описывает отношение между атрибутами в отношении.

Поддержка не соответствует:


92
@webXL, ГДЕ работает с одной записью, ХАВИНГ работает с группой
bjan

8
@gbn Можно ли включить Id в результаты? Тогда было бы легче удалить эти дубликаты впоследствии.
user797717

13
@ user797717: вам понадобится MIN (ID), а затем удалить значения ID, которые не являются последними, если значения MIN (ID)
gbn

1
Как насчет случаев, когда любой из столбцов имеет нулевые значения?
Анкит Дхингра

1
Большое спасибо за это, и да, это работает в Oracle, хотя мне нужна была уникальность условия, а не>1 =1
Билл Нейлор

370

попробуй это:

declare @YourTable table (id int, name varchar(10), email varchar(50))

INSERT @YourTable VALUES (1,'John','John-email')
INSERT @YourTable VALUES (2,'John','John-email')
INSERT @YourTable VALUES (3,'fred','John-email')
INSERT @YourTable VALUES (4,'fred','fred-email')
INSERT @YourTable VALUES (5,'sam','sam-email')
INSERT @YourTable VALUES (6,'sam','sam-email')

SELECT
    name,email, COUNT(*) AS CountOf
    FROM @YourTable
    GROUP BY name,email
    HAVING COUNT(*)>1

ВЫВОД:

name       email       CountOf
---------- ----------- -----------
John       John-email  2
sam        sam-email   2

(2 row(s) affected)

если вы хотите идентификаторы дупс, используйте это:

SELECT
    y.id,y.name,y.email
    FROM @YourTable y
        INNER JOIN (SELECT
                        name,email, COUNT(*) AS CountOf
                        FROM @YourTable
                        GROUP BY name,email
                        HAVING COUNT(*)>1
                    ) dt ON y.name=dt.name AND y.email=dt.email

ВЫВОД:

id          name       email
----------- ---------- ------------
1           John       John-email
2           John       John-email
5           sam        sam-email
6           sam        sam-email

(4 row(s) affected)

чтобы удалить дубликаты, попробуйте:

DELETE d
    FROM @YourTable d
        INNER JOIN (SELECT
                        y.id,y.name,y.email,ROW_NUMBER() OVER(PARTITION BY y.name,y.email ORDER BY y.name,y.email,y.id) AS RowRank
                        FROM @YourTable y
                            INNER JOIN (SELECT
                                            name,email, COUNT(*) AS CountOf
                                            FROM @YourTable
                                            GROUP BY name,email
                                            HAVING COUNT(*)>1
                                        ) dt ON y.name=dt.name AND y.email=dt.email
                   ) dt2 ON d.id=dt2.id
        WHERE dt2.RowRank!=1
SELECT * FROM @YourTable

ВЫВОД:

id          name       email
----------- ---------- --------------
1           John       John-email
3           fred       John-email
4           fred       fred-email
5           sam        sam-email

(4 row(s) affected)


72

Если вы хотите удалить дубликаты, вот гораздо более простой способ сделать это, чем найти четные / нечетные строки в тройном суб-выборе:

SELECT id, name, email 
FROM users u, users u2
WHERE u.name = u2.name AND u.email = u2.email AND u.id > u2.id

И так, чтобы удалить:

DELETE FROM users
WHERE id IN (
    SELECT id/*, name, email*/
    FROM users u, users u2
    WHERE u.name = u2.name AND u.email = u2.email AND u.id > u2.id
)

Гораздо проще читать и понимать ИМХО

Примечание . Единственная проблема заключается в том, что вы должны выполнить запрос, пока не будет удалено ни одной строки, поскольку каждый раз удаляется только 1 из каждого дубликата.


2
Красиво и легко читается; Я хотел бы найти способ, чтобы удалить несколько повторяющихся строк за один раз, хотя.
Дикон Рид

1
Это не работает для меня, как я получаюYou can't specify target table 'users' for update in FROM clause
Whitecat

1
@Whitecat кажется простой проблемой MySQL: stackoverflow.com/questions/4429319/…
AncAinu

1
Терпит неудачу для меня. Я получаю: «DBD :: CSV :: st выполнить не удалось: использование неинициализированного значения $ _ [1] в хеш-элементе по адресу /Users/hornenj/perl5/perlbrew/perls/perl-5.26.0/lib/site_perl/5.26. 0 / SQL / Eval.pm строка 43 "
Найджел Хорн

1
Я думаю, что условие where должно быть «u.name = u2.name AND u.email = u2.email AND (u.id> u2.id ИЛИ u2.id> u.id)», не так ли?
GiveEmTheBoot

48

Попробуйте следующее:

SELECT * FROM
(
    SELECT Id, Name, Age, Comments, Row_Number() OVER(PARTITION BY Name, Age ORDER By Name)
        AS Rank 
        FROM Customers
) AS B WHERE Rank>1

3
Небольшое изменение в SELECT * помогло мне найти час поиска. Я никогда не использовал OVER (PARTITION BY прежде). Я не перестаю удивляться тому, как много способов сделать то же самое в SQL!
Джо Рудер


28

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

SELECT GROUP_CONCAT( id )
FROM users
GROUP BY email
HAVING ( COUNT(email) > 1 )

2
Кажется, это синтаксическая работа с сахаром. Хорошая находка.
Chef_Code

3
Имейте в виду, что GROUP_CONCATэто остановится после некоторой заданной длины, поэтому вы можете не получить все ids.
v010dya

24

попробуй этот код

WITH CTE AS

( SELECT Id, Name, Age, Comments, RN = ROW_NUMBER()OVER(PARTITION BY Name,Age ORDER BY ccn)
FROM ccnmaster )
select * from CTE 

23

Это выбирает / удаляет все дублирующиеся записи, кроме одной записи из каждой группы дубликатов. Таким образом, удаление оставляет все уникальные записи + одну запись из каждой группы дубликатов.

Выберите дубликаты:

SELECT *
FROM table
WHERE
    id NOT IN (
        SELECT MIN(id)
        FROM table
        GROUP BY column1, column2
);

Удалить дубликаты:

DELETE FROM table
WHERE
    id NOT IN (
        SELECT MIN(id)
        FROM table
        GROUP BY column1, column2
);

Помните о большом количестве записей, это может вызвать проблемы с производительностью.


2
Ошибка в запросе на удаление - Вы не можете указать целевую таблицу «города» для обновления в предложении FROM
Али Азар

2
Нет ни таблицы «города», ни предложения об обновлении. Что вы имеете в виду? Где ошибка в запросе на удаление?
Мартин Силовски,

2
Как это работает с данными ОП?
Торок

3
Что означает «ОП»?
Мартин

19

Если вы работаете с Oracle, этот способ будет предпочтительнее:

create table my_users(id number, name varchar2(100), email varchar2(100));

insert into my_users values (1, 'John', 'asd@asd.com');
insert into my_users values (2, 'Sam', 'asd@asd.com');
insert into my_users values (3, 'Tom', 'asd@asd.com');
insert into my_users values (4, 'Bob', 'bob@asd.com');
insert into my_users values (5, 'Tom', 'asd@asd.com');

commit;

select *
  from my_users
 where rowid not in (select min(rowid) from my_users group by name, email);

15
select name, email
, case 
when ROW_NUMBER () over (partition by name, email order by name) > 1 then 'Yes'
else 'No'
end "duplicated ?"
from users

2
Ответы с кодом только осуждаются при переполнении стека. Не могли бы вы объяснить, почему это отвечает на вопрос?
Рич Беннер

2
@RichBenner: я не нашел ответа, такого как, каждая строка в результате и которая говорит нам, какие из них являются повторяющимися, а какие нет, и что не нужно группировать, потому что если мы хотим объединить это Запрос с любой другой группой запросов не является хорошим вариантом.
Нарендра

2
Добавление идентификатора в оператор выбора и фильтрация дубликатов дает вам возможность удалить дубликаты идентификаторов и сохранить их.
Антуан Рейнхольд Бертран

12

Если вы хотите увидеть, есть ли в вашей таблице повторяющиеся строки, я использовал ниже Query:

create table my_table(id int, name varchar(100), email varchar(100));

insert into my_table values (1, 'shekh', 'shekh@rms.com');
insert into my_table values (1, 'shekh', 'shekh@rms.com');
insert into my_table values (2, 'Aman', 'aman@rms.com');
insert into my_table values (3, 'Tom', 'tom@rms.com');
insert into my_table values (4, 'Raj', 'raj@rms.com');


Select COUNT(1) As Total_Rows from my_table 
Select Count(1) As Distinct_Rows from ( Select Distinct * from my_table) abc 

11

Это легкая вещь, которую я придумал. Он использует общее табличное выражение (CTE) и окно раздела (я думаю, что эти функции есть в SQL 2008 и более поздних версиях).

Этот пример находит всех студентов с одинаковыми именами и документами. Поля, которые вы хотите проверить на дублирование, идут в предложении OVER. Вы можете включить любые другие поля, которые вы хотите в проекции.

with cte (StudentId, Fname, LName, DOB, RowCnt)
as (
SELECT StudentId, FirstName, LastName, DateOfBirth as DOB, SUM(1) OVER (Partition By FirstName, LastName, DateOfBirth) as RowCnt
FROM tblStudent
)
SELECT * from CTE where RowCnt > 1
ORDER BY DOB, LName


10

Как мы можем посчитать дублированные значения ?? или это повторяется 2 раза или больше 2. просто посчитайте их, а не по группам.

так просто как

select COUNT(distinct col_01) from Table_01

2
Как бы это работало на вопрос, который задали? Это не дает строк, которые дублируют информацию в нескольких столбцах (например, «электронная почта» и «имя») в разных строках.
Jeroen

10

Используя CTE, мы также можем найти двойное значение

with MyCTE
as
(
select Name,EmailId,ROW_NUMBER() over(PARTITION BY EmailId order by id) as Duplicate from [Employees]

)
select * from MyCTE where Duplicate>1

9
 select emp.ename, emp.empno, dept.loc 
          from emp
 inner join dept 
          on dept.deptno=emp.deptno
 inner join
    (select ename, count(*) from
    emp
    group by ename, deptno
    having count(*) > 1)
 t on emp.ename=t.ename order by emp.ename
/

8

SELECT id, COUNT(id) FROM table1 GROUP BY id HAVING COUNT(id)>1;

Я думаю, что это будет работать правильно для поиска повторяющихся значений в определенном столбце.


6
Это не добавляет ничего к лучшему ответу и технически даже не отличается от кода ОП, размещенного в вопросе.
Jeroen


6

Это также должно работать, может быть, попробовать.

  Select * from Users a
            where EXISTS (Select * from Users b 
                where (     a.name = b.name 
                        OR  a.email = b.email)
                     and a.ID != b.id)

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


5

Если вы хотите найти дубликаты данных (по одному или нескольким критериям) и выбрать фактические строки.

with MYCTE as (
    SELECT DuplicateKey1
        ,DuplicateKey2 --optional
        ,count(*) X
    FROM MyTable
    group by DuplicateKey1, DuplicateKey2
    having count(*) > 1
) 
SELECT E.*
FROM MyTable E
JOIN MYCTE cte
ON E.DuplicateKey1=cte.DuplicateKey1
    AND E.DuplicateKey2=cte.DuplicateKey2
ORDER BY E.DuplicateKey1, E.DuplicateKey2, CreatedAt

http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/


4
SELECT name, email,COUNT(email) 
FROM users 
WHERE email IN (
    SELECT email 
    FROM users 
    GROUP BY email 
    HAVING COUNT(email) > 1)

Вы не можете использовать COUNTбез GROUP BY, если это не относится ко всей таблице.
RalfFriedl

Без группы By вы использовали COUNT, но здесь я сделал опечатку, чтобы написать COUNT
Мохаммад Неамул Ислам

3

Удалить записи, имена которых повторяются

;WITH CTE AS    
(

    SELECT ROW_NUMBER() OVER (PARTITION BY name ORDER BY name) AS T FROM     @YourTable    
)

DELETE FROM CTE WHERE T > 1

3

Для проверки из дубликата записи в таблице.

select * from users s 
where rowid < any 
(select rowid from users k where s.name = k.name and s.email = k.email);

или

select * from users s 
where rowid not in 
(select max(rowid) from users k where s.name = k.name and s.email = k.email);

Удалить дубликат записи в таблице.

delete from users s 
where rowid < any 
(select rowid from users k where s.name = k.name and s.email = k.email);

или

delete from users s 
where rowid not in 
(select max(rowid) from users k where s.name = k.name and s.email = k.email);


1

Мы можем использовать здесь, которые работают с агрегатными функциями, как показано ниже

create table #TableB (id_account int, data int, [date] date)
insert into #TableB values (1 ,-50, '10/20/2018'),
(1, 20, '10/09/2018'),
(2 ,-900, '10/01/2018'),
(1 ,20, '09/25/2018'),
(1 ,-100, '08/01/2018')  

SELECT id_account , data, COUNT(*)
FROM #TableB
GROUP BY id_account , data
HAVING COUNT(id_account) > 1

drop table #TableB

Здесь в качестве двух полей id_account и data используются Count (*). Таким образом, он выдаст все записи, которые имеют более одного раза одинаковые значения в обоих столбцах.

Мы по какой-то причине ошибочно пропустили добавление каких-либо ограничений в таблицу SQL-сервера, и записи были вставлены дубликаты во все столбцы с интерфейсным приложением. Затем мы можем использовать запрос ниже, чтобы удалить дубликат запроса из таблицы.

SELECT DISTINCT * INTO #TemNewTable FROM #OriginalTable
TRUNCATE TABLE #OriginalTable
INSERT INTO #OriginalTable SELECT * FROM #TemNewTable
DROP TABLE #TemNewTable

Здесь мы взяли все отличные записи исходной таблицы и удалили записи исходной таблицы. Мы снова вставили все различные значения из новой таблицы в исходную таблицу, а затем удалили новую таблицу.


1

Вы можете попробовать это

SELECT NAME, EMAIL, COUNT(*)
FROM USERS
GROUP BY 1,2
HAVING COUNT(*) > 1

1

Самое главное здесь - иметь самую быструю функцию. Также должны быть идентифицированы индексы дубликатов. Самостоятельное объединение является хорошим вариантом, но для более быстрой функции лучше сначала найти строки, которые имеют дубликаты, а затем объединить с исходной таблицей для поиска идентификатора дублированных строк. Наконец, порядок по любому столбцу, кроме ID, чтобы дублированные строки были рядом друг с другом.

SELECT u.*
FROM users AS u
JOIN (SELECT username, email
      FROM users
      GROUP BY username, email
      HAVING COUNT(*)>1) AS w
ON u.username=w.username AND u.email=w.email
ORDER BY u.email;

0

Вы можете использовать ключевое слово SELECT DISTINCT, чтобы избавиться от дубликатов. Вы также можете фильтровать по имени и получить всех с этим именем на столе.


0

Точный код будет отличаться в зависимости от того, хотите ли вы также найти дублирующиеся строки или только разные идентификаторы с одинаковыми адресом электронной почты и именем. Если id является первичным ключом или иным образом имеет уникальное ограничение, это различие не существует, но вопрос не определяет это. В первом случае вы можете использовать код, приведенный в нескольких других ответах:

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

В последнем случае вы бы использовали:

SELECT name, email, COUNT(DISTINCT id)
FROM users
GROUP BY name, email
HAVING COUNT(DISTINCT id) > 1
ORDER BY COUNT(DISTINCT id) DESC
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.