Пошук повторюваних значень у таблиці SQL


1931

Легко знайти дублікати з одним полем:

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.
Е. ван Путтен

що мені потрібно - це ідентифікатор записів із дублюваною електронною поштою
Маркос Ді Паоло,

Відповіді:


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

Просто згрупуйте обидві стовпці.

Примітка. Старіший стандарт ANSI полягає у тому, щоб усі групи, що не агрегуються, у групі GROUP BY, але це змінилося з ідеєю "функціональної залежності" :

У теорії реляційних баз даних функціональна залежність є обмеженням між двома наборами атрибутів у відношенні до бази даних. Іншими словами, функціональна залежність - це обмеження, яке описує зв'язок між атрибутами у відношенні.

Підтримка не відповідає:


92
@webXL WHERE працює з одиночним записом HAVING працює з групою
bjan

8
@gbn Чи можна включити Id в результати? Тоді було б простіше видалити ці дублікати згодом.
користувач797717

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 Execute failed: Використання неініціалізованого значення $ _ [1] в хеш-елементі за адресою /Users/hornenj/perl5/perlbrew/perls/perl-5.26.0/lib/site_perl/5.26. 0 / SQL / Eval.pm рядок 43 "
Найджел Хорн

1
Я думаю, що де пункт повинен бути "u.name = u2.name AND u.email = u2.email AND (u.id> u2.id АБО2.2.> 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 * допомогла мені вирішити годинний пошук. Я ніколи не використовував НАДЕЖ (РОЗДІЛУВАННЯ раніше. Я ніколи не перестаю дивуватися, скільки способів зробити те саме в SQL!
Джо Рудер,


28

Трохи запізнюємось на вечірку, але я знайшов дійсно класний спосіб пошуку всіх повторюваних ідентифікаторів:

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
Помилка в запиті на видалення - Ви не можете вказати цільову таблицю "міст" для оновлення у пункті ВІД
Ali Azhar

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
Відповіді на код лише накинуті на стек Overflow, чи можете ви пояснити, чому це відповідає на це питання?
Річ Беннер

2
@RichBenner: Я не знайшов такої відповіді, як, кожен і кожен рядок у результаті, який повідомляє нам, які всі повторювані рядки, а які не з одного погляду, а які не згрупувати, тому що якщо ми хочемо поєднати це запит з будь-якою іншою групою запитів від - це не найкращий варіант.
Нарендра

2
Додавши Id до оператора select і фільтруючи на дублювання, він дає можливість видалити дублювані ідентифікатори та продовжувати кожен.
Антуан

12

Якщо ви хочете побачити, чи є у вашій таблиці якісь повторювані рядки, я використав нижче Запит:

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 та пізніших версіях).

Цей приклад знаходить усіх учнів із подвійним ім'ям та dob. Поля, які ви хочете перевірити на дублювання, входять у пункт 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
Як би це працювало на запитання? Це не дає рядки, які дублюють інформацію в декількох стовпцях (наприклад, "електронна пошта" та "ім'я") в різних рядках.
Єроен

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
/

7

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

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


6
Це не зовсім нічого додає до головної відповіді , а технічно навіть не дуже відрізняється від коду ОП, розміщеного у запитанні.
Єроен

7
SELECT * FROM users u where rowid = (select max(rowid) from users u1 where
u.email=u1.email);

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)

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


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, якщо це не стосується всієї таблиці.
РальфФрідл

Без групи Ви використовували COUNT, але тут я робив помилку набору тексту, щоб писати COUNT
Mohammad Neamul Islam

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

Тут як Count (*) використовуються два поля id_account та дані. Таким чином, він дасть всі записи, які мають більше ніж один раз однакові значення в обох стовпцях.

Ми чомусь помилково пропустили додавання будь-яких обмежень у таблицю 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.