Menemukan nilai duplikat dalam tabel SQL

1936

Sangat mudah untuk menemukan duplikat dengan satu bidang:

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

Jadi kalau kita punya meja

ID   NAME   EMAIL
1    John   [email protected]
2    Sam    [email protected]
3    Tom    [email protected]
4    Bob    [email protected]
5    Tom    [email protected]

Permintaan ini akan memberi kita John, Sam, Tom, Tom karena mereka semua memiliki yang sama email.

Namun, yang saya inginkan adalah mendapatkan duplikat dengan yang sama email dan name .

Artinya, saya ingin mendapatkan "Tom", "Tom".

Alasan saya membutuhkan ini: Saya membuat kesalahan, dan diizinkan untuk memasukkan nilai duplikat namedan email. Sekarang saya perlu menghapus / mengubah duplikat, jadi saya harus menemukannya terlebih dahulu.

Alex
sumber
28
Saya tidak berpikir itu akan membiarkan Anda memilih nama dalam sampel pertama Anda karena itu tidak dalam fungsi agregat. "Berapa jumlah alamat email yang cocok dan nama mereka" adalah beberapa logika yang rumit ...
sXe
3
Menemukan bahwa ini tidak berfungsi dengan server MSSQL karena namebidang di SELECT.
E. van Putten
yang saya butuhkan adalah id catatan dengan duplikat email
Marcos Di Paolo

Jawaban:

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

Cukup kelompokkan pada kedua kolom.

Catatan: standar ANSI yang lebih lama adalah memiliki semua kolom yang tidak diagregasi dalam GROUP BY tetapi ini telah berubah dengan gagasan "ketergantungan fungsional" :

Dalam teori basis data relasional, ketergantungan fungsional adalah kendala antara dua set atribut dalam suatu hubungan dari database. Dengan kata lain, dependensi fungsional adalah kendala yang menggambarkan hubungan antar atribut dalam suatu relasi.

Dukungan tidak konsisten:

gbn
sumber
92
@webXL WHERE bekerja dengan rekaman tunggal HAVING bekerja dengan grup
bjan
8
@ gbn Apakah mungkin untuk memasukkan ID dalam hasil? Maka akan lebih mudah untuk menghapus duplikat itu sesudahnya.
user797717
13
@ user797717: Anda harus memiliki MIN (ID) dan kemudian menghapus untuk nilai ID bukan yang terakhir jika MIN (ID) nilai
gbn
1
Bagaimana dengan kasus di mana salah satu kolom memiliki nilai nol?
Ankit Dhingra
1
Terima kasih banyak untuk ini, dan ya itu berhasil di Oracle, meskipun saya membutuhkan keunikan dari kondisinya, jadi daripada>1 =1
Bill Naylor
370

coba ini:

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

KELUARAN:

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

(2 row(s) affected)

jika Anda ingin ID dari dups gunakan ini:

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

KELUARAN:

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

(4 row(s) affected)

untuk menghapus duplikat coba:

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

KELUARAN:

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

(4 row(s) affected)
KM.
sumber
127

Coba ini:

SELECT name, email
FROM users
GROUP BY name, email
HAVING ( COUNT(*) > 1 )
Chris Van Opstal
sumber
72

Jika Anda ingin menghapus duplikat, berikut ini cara yang lebih sederhana untuk melakukannya daripada harus menemukan baris genap / ganjil ke dalam tiga sub-pilih:

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

Dan untuk menghapus:

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
)

Jauh lebih mudah untuk membaca dan memahami IMHO

Catatan: Satu-satunya masalah adalah Anda harus mengeksekusi permintaan sampai tidak ada baris yang dihapus, karena Anda hanya menghapus 1 dari setiap duplikat setiap kali

AncAinu
sumber
2
Bagus dan mudah dibaca; Saya ingin menemukan cara yang menghapus beberapa baris duplikat sekaligus.
Dickon Reed
1
Ini tidak bekerja untuk saya seperti yang saya dapatkanYou can't specify target table 'users' for update in FROM clause
Whitecat
1
@ Whitecat sepertinya masalah MySQL sederhana: stackoverflow.com/questions/4429319/...
AncAinu
1
Gagal bagiku. Saya mendapatkan: "DBD :: CSV :: st execute gagal: Penggunaan nilai yang tidak diinisialisasi $ _ [1] dalam elemen hash di / Pengguna /hornenj/perl5/perlbrew/perls/perl-5.26.0/lib/site_perl/5.26. 0 / SQL / Eval.pm baris 43 "
Nigel Horne
1
Saya pikir di mana klausa seharusnya "u.name = u2.name DAN u.email = u2.email AND (u.id> u2.id OR u2.id> u.id)" bukan?
GiveEmTheBoot
48

Coba yang berikut ini:

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
gaurav singh
sumber
3
Sedikit perubahan ke SELECT * membantu saya menyelesaikan pencarian satu jam. Saya tidak pernah menggunakan OVER (PARTISI OLEH sebelumnya. Saya tidak pernah berhenti kagum pada berapa banyak cara untuk melakukan hal yang sama dalam SQL!
Joe Ruder
33
 SELECT name, email 
    FROM users
    WHERE email in
    (SELECT email FROM users
    GROUP BY email 
    HAVING COUNT(*)>1)
PRADEEPTA VIRLLEY
sumber
28

Sedikit terlambat ke pesta tetapi saya menemukan solusi yang sangat keren untuk menemukan semua duplikat ID:

SELECT GROUP_CONCAT( id )
FROM users
GROUP BY email
HAVING ( COUNT(email) > 1 )
Indivision Dev
sumber
2
Tampaknya menjadi pekerjaan gula sintaksis. Temuan yang bagus.
Chef_Code
3
Perlu diingat bahwa GROUP_CONCATakan berhenti setelah beberapa panjang yang telah ditentukan, sehingga Anda mungkin tidak mendapatkan semua id.
v010dya
24

coba kode ini

WITH CTE AS

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

Ini memilih / menghapus semua rekaman duplikat kecuali satu catatan dari setiap kelompok duplikat. Jadi, penghapusan membuat semua catatan unik + satu catatan dari setiap grup duplikat.

Pilih duplikat:

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

Hapus duplikat:

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

Waspadai jumlah catatan yang lebih besar, ini dapat menyebabkan masalah kinerja.

Martin Silovský
sumber
2
Galat saat menghapus kueri - Anda tidak dapat menentukan tabel target 'kota' untuk pembaruan dalam klausa FROM
Ali Azhar
2
Tidak ada tabel 'kota' atau klausa pembaruan. Apa maksudmu? Di mana ada kesalahan dalam kueri penghapusan?
Martin Silovský
2
Bagaimana cara kerjanya dengan data OP?
thoroc
3
Apa arti "OP"?
Martin Silovský
19

Jika Anda bekerja dengan Oracle, cara ini lebih disukai:

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

insert into my_users values (1, 'John', '[email protected]');
insert into my_users values (2, 'Sam', '[email protected]');
insert into my_users values (3, 'Tom', '[email protected]');
insert into my_users values (4, 'Bob', '[email protected]');
insert into my_users values (5, 'Tom', '[email protected]');

commit;

select *
  from my_users
 where rowid not in (select min(rowid) from my_users group by name, email);
xDBA
sumber
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
Narendra
sumber
2
Kode hanya jawaban yang disukai di Stack Overflow, bisakah Anda menjelaskan mengapa ini menjawab pertanyaan?
Rich Benner
2
@RichBenner: Saya tidak menemukan respons seperti, setiap & setiap baris dalam hasil dan yang memberi tahu kita mana semua baris duplikat dan yang tidak dalam satu pandangan dan yang tidak dikelompokkan, karena jika kita ingin menggabungkan ini kueri dengan grup kueri lain apa pun bukanlah pilihan yang baik.
Narendra
2
Menambahkan Id ke pernyataan pilih dan memfilter pada duplikat, itu memberi Anda kemungkinan untuk menghapus id yang digandakan dan terus masing-masing.
Antoine Reinhold Bertrand
12

Jika Anda ingin melihat apakah ada baris duplikat di tabel Anda, saya menggunakan Query di bawah ini:

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

insert into my_table values (1, 'shekh', '[email protected]');
insert into my_table values (1, 'shekh', '[email protected]');
insert into my_table values (2, 'Aman', '[email protected]');
insert into my_table values (3, 'Tom', '[email protected]');
insert into my_table values (4, 'Raj', '[email protected]');


Select COUNT(1) As Total_Rows from my_table 
Select Count(1) As Distinct_Rows from ( Select Distinct * from my_table) abc 
shekhar Kumar
sumber
11

Ini adalah hal mudah yang saya buat. Ini menggunakan ekspresi tabel umum (CTE) dan jendela partisi (saya pikir fitur ini ada di SQL 2008 dan yang lebih baru).

Contoh ini menemukan semua siswa dengan nama duplikat dan dob. Kolom yang ingin Anda periksa duplikatnya masuk dalam klausa OVER. Anda dapat memasukkan bidang lain yang Anda inginkan dalam proyeksi.

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
Darrel Lee
sumber
11
select id,name,COUNT(*) from user group by Id,Name having COUNT(*)>1
Debendra Dash
sumber
10

Bagaimana kita bisa menghitung nilai duplikat ?? baik itu diulang 2 kali atau lebih besar dari 2. hitung saja, bukan kelompok bijaksana.

sesederhana

select COUNT(distinct col_01) from Table_01
Muhammad Tahir
sumber
2
Bagaimana cara kerjanya untuk pertanyaan seperti yang diajukan? Ini tidak memberikan baris yang menggandakan informasi dalam banyak kolom (misalnya "email" dan "nama") di baris yang berbeda.
Jeroen
10

Dengan Menggunakan CTE juga kita dapat menemukan nilai duplikat seperti ini

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
Debendra Dash
sumber
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
/
naveed
sumber
8

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

Saya pikir ini akan berfungsi dengan baik untuk mencari nilai yang berulang di kolom tertentu.

pengguna4877838
sumber
6
Ini tidak cukup menambahkan apa pun ke jawaban atas , dan secara teknis bahkan tidak benar-benar berbeda dari kode OP yang diposting dalam pertanyaan.
Jeroen
7
SELECT * FROM users u where rowid = (select max(rowid) from users u1 where
u.email=u1.email);
Panky031
sumber
6

Ini juga harus bekerja, mungkin mencobanya.

  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)

Sangat baik dalam kasus Anda Jika Anda mencari duplikat yang memiliki semacam awalan atau perubahan umum seperti misalnya domain baru dalam surat. maka Anda dapat menggunakan ganti () di kolom ini

veritaS
sumber
5

Jika Anda ingin menemukan data duplikat (oleh satu atau beberapa kriteria) dan pilih baris yang sebenarnya.

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/

Lauri Lubi
sumber
4
SELECT name, email,COUNT(email) 
FROM users 
WHERE email IN (
    SELECT email 
    FROM users 
    GROUP BY email 
    HAVING COUNT(email) > 1)
Mohammad Neamul Islam
sumber
Anda tidak dapat menggunakan COUNTtanpa GROUP BY, kecuali itu mengacu pada seluruh tabel.
RalfFriedl
Tanpa Grup Oleh Anda menggunakan COUNT tetapi di sini saya telah melakukan kesalahan pengetikan untuk menulis COUNT
Mohammad Neamul Islam
3

Untuk menghapus catatan yang namanya duplikat

;WITH CTE AS    
(

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

DELETE FROM CTE WHERE T > 1
Sheriff
sumber
3

Untuk Memeriksa Dari Rekam rangkap dalam tabel.

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

atau

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

Untuk menghapus catatan duplikat dalam sebuah tabel.

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

atau

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

SELECT column_name,COUNT(*) FROM TABLE_NAME GROUP BY column1, HAVING COUNT(*) > 1;

rahul kumar
sumber
1

Kita dapat menggunakan memiliki di sini yang berfungsi pada fungsi agregat seperti yang ditunjukkan di bawah ini

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

Di sini sebagai dua bidang, id_account dan data digunakan dengan Count (*). Jadi, itu akan memberikan semua catatan yang memiliki nilai lebih dari satu kali sama di kedua kolom.

Kami beberapa alasan keliru kami telah gagal untuk menambahkan kendala dalam tabel SQL server dan catatan telah dimasukkan duplikat di semua kolom dengan aplikasi front-end. Kemudian kita bisa menggunakan kueri di bawah ini untuk menghapus kueri duplikat dari tabel.

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

Di sini kami telah mengambil semua catatan berbeda dari tabel orignal dan menghapus catatan dari tabel asli. Sekali lagi kami memasukkan semua nilai berbeda dari tabel baru ke tabel asli dan kemudian menghapus tabel baru.

Suraj Kumar
sumber
1

Anda mungkin ingin mencoba ini

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

Yang paling penting di sini adalah memiliki fungsi tercepat. Indeks duplikat juga harus diidentifikasi. Bergabung sendiri adalah pilihan yang baik tetapi untuk memiliki fungsi yang lebih cepat lebih baik untuk pertama kali menemukan baris yang memiliki duplikat dan kemudian bergabung dengan tabel asli untuk menemukan id dari baris yang digandakan. Terakhir, pesanlah dengan kolom apa pun kecuali id ​​untuk menduplikasi baris di dekat satu sama lain.

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;
RyanAbnavi
sumber
0

Anda dapat menggunakan kata kunci SELECT DISTINCT untuk menghilangkan duplikat. Anda juga bisa memfilter menurut nama dan membuat semua orang dengan nama itu di atas meja.

Parkofadown
sumber
0

Kode pastinya akan berbeda tergantung pada apakah Anda ingin menemukan baris duplikat juga atau hanya id yang berbeda dengan email dan nama yang sama. Jika id adalah kunci utama atau memiliki kendala unik, perbedaan ini tidak ada, tetapi pertanyaannya tidak menentukan ini. Dalam kasus sebelumnya, Anda dapat menggunakan kode yang diberikan dalam beberapa jawaban lain:

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

Dalam kasus terakhir Anda akan menggunakan:

SELECT name, email, COUNT(DISTINCT id)
FROM users
GROUP BY name, email
HAVING COUNT(DISTINCT id) > 1
ORDER BY COUNT(DISTINCT id) DESC
MEMBASAHI
sumber