Menemukan duplikat baris di SQL Server


231

Saya memiliki database organisasi SQL Server, dan ada banyak baris duplikat. Saya ingin menjalankan pernyataan pilih untuk mengambil semua ini dan jumlah dupes, tetapi juga mengembalikan id yang terkait dengan masing-masing organisasi.

Pernyataan seperti:

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

Akan mengembalikan sesuatu seperti

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

Tapi saya juga ingin mengambil ID mereka. Apakah ada cara untuk melakukan ini? Mungkin seperti a

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

Alasannya adalah bahwa ada juga tabel terpisah dari pengguna yang menautkan ke organisasi-organisasi ini, dan saya ingin menyatukan mereka (oleh karena itu hapus dupes sehingga pengguna menautkan ke organisasi yang sama dan bukan org dupe). Tapi saya ingin berpisah secara manual sehingga saya tidak mengacaukan apa pun, tetapi saya masih membutuhkan pernyataan yang mengembalikan ID dari semua dupe orgs sehingga saya bisa melihat daftar pengguna.

Jawaban:


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
Adakah batasan dalam kueri ini, misalnya jika jumlah rekaman adalah 10 juta ditambah?
Uap

3
@ Timam Anda benar: jawaban ini tidak efisien dalam database yang lebih besar dengan jutaan catatan. Memilih GroupBy / Setelah jawaban diajukan oleh Aykut, yang dapat lebih dioptimalkan oleh database. Satu pengecualian: Saya sarankan menggunakan Count (0) daripada Count (*), untuk mempermudah.
Mike Christian

1
@ Mike - mengapa Hitung (0) vs Hitung (*)?
KornMuffin

2
@KornMuffin Dalam retrospeksi, komentar saya tentang Count () tidak berlaku. Menggunakan evaluasi non-nol di Count () berguna hanya ketika Anda ingin menghitung hasil non-nol yang dikembalikan oleh gabungan luar. Jika tidak, gunakan Count (*). Penjelasan yang bagus ditemukan di sini .
Mike Christian

gunakan isnull()untuk kolom yang dapat dibatalkan pada onbagian
Arif Ulusoy

92

Anda dapat menjalankan kueri berikut dan menemukan duplikat dengan max(id)dan menghapus baris itu.

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

Tetapi Anda harus menjalankan kueri ini beberapa kali.


Anda harus menjalankannya tepat MAX( COUNT(*) ) - 1waktu, yang mungkin masih layak.
DerMike

1
hai adalah cara mereka untuk mendapatkan semua id bukan max id seperti untuk 2 saya dapat menggunakan max dan min tetapi bagaimana dengan lebih dari 2? @DerMike
Arijit Mukherjee

31

Anda dapat melakukannya seperti ini:

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

Jika Anda ingin mengembalikan hanya catatan yang dapat dihapus (meninggalkan masing-masing), Anda dapat menggunakan:

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

Sunting: SQL Server 2000 tidak memiliki fungsi ROW_NUMBER (). Sebagai gantinya, Anda dapat menggunakan:

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

Pernyataan pertama berhasil, tetapi yang kedua sepertinya tidak berhasil.
xtine

SQL Server tampaknya tidak dapat mengenali row_number ()?
xtine

Ah ... apakah Anda memiliki versi SQL Server yang lebih lama? Saya percaya ini diperkenalkan di SQL Server 2005.
Paul

3
terima kasih lagi, setiap kali saya perlu melakukan ini, saya sampai di sini dan MENCINTAIMU
workabyte

9

Solusi yang ditandai sebagai benar tidak berfungsi untuk saya, tetapi saya menemukan jawaban ini sangat bagus: Dapatkan daftar baris duplikat di MySql

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

Anda akan mendapatkan banyak dupes di set hasil, jadi Anda harus menghadapinya juga.
Renan

1
Jika id adalah numerik, memeriksa n1.id > n2.idakan mencegah setiap pasangan muncul dua kali.
dibintangi

9

Anda dapat mencoba ini, yang terbaik untuk Anda

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

cara apa pun untuk mendapatkan semua id dalam kolom koma atau kolom berbeda
Arijit Mukherjee

6

Jika Anda ingin menghapus duplikat:

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]

Untuk menemukan duplikat Rekam 1) Menggunakan 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) Dengan Menggunakan GroupBy

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

Ini solusi tercepat di sini, ketika MEMILIH data lebih dari 10m baris itu. Terima kasih
Fandango68

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

Jadi catatan dengan rowum> 1 akan menjadi rekaman duplikat di tabel Anda. 'Partisi oleh' kelompok pertama oleh catatan dan kemudian membuat cerita bersambung dengan memberi mereka nomor seri. Jadi rownum> 1 akan menjadi duplikat catatan yang bisa dihapus.


Saya suka ini karena memungkinkan Anda untuk dengan mudah menambahkan lebih banyak kolom dalam klausa pilih dalam. Jadi, jika Anda ingin mengembalikan kolom lain dari tabel 'Organisasi' Anda tidak harus melakukan 'grup dengan' pada kolom-kolom itu.
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

Anda memiliki beberapa cara untuk Pilih duplicate rows .

untuk solusi saya, pertimbangkan dulu tabel ini sebagai contoh

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

Solusi pertama:

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

Solusi kedua: Gunakan identitybidang

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

dan akhir semua solusi gunakan perintah ini

DROP TABLE #Employee

0

saya pikir saya tahu apa yang Anda butuhkan saya perlu mencampur antara jawaban dan saya pikir saya mendapatkan solusi yang ia inginkan:

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

memiliki max id akan memberi Anda id dari dublicate dan yang asli yang ia minta:

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)

hanya hal menyedihkan yang Anda keluarkan dalam formulir ini

id , name , dubid , name

semoga tetap membantu


0

Misalkan kita memiliki tabel 'Siswa' tabel dengan 2 kolom:

  • student_id int
  • student_name varchar

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

Sekarang kami ingin melihat rekaman duplikat. Gunakan kueri ini:

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

Saya mendapat opsi yang lebih baik untuk mendapatkan rekaman duplikat di tabel

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

Hasil kueri di atas menunjukkan semua nama duplikat dengan id siswa yang unik dan jumlah kejadian duplikat

Klik di sini untuk melihat hasil dari 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

Saya menggunakan dua metode untuk menemukan baris duplikat. Metode 1 adalah yang paling terkenal menggunakan grup oleh dan memiliki. Metode 2 menggunakan CTE - Common Table Expression .

Seperti yang disebutkan oleh @RedFilter cara ini juga benar. Banyak kali saya menemukan metode CTE juga berguna bagi saya.

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

Dalam contoh di atas, kami mengumpulkan hasilnya dengan menemukan kejadian berulang menggunakan ROW_NUMBER dan PARTITION BY. Kemudian kami menerapkan mana klausa untuk memilih hanya baris yang pada hitung ulang lebih dari 1. Semua hasilnya dikumpulkan tabel CTE dan bergabung dengan tabel Organisasi.

Sumber: CodoBee


-2

Mencoba

SELECT orgName, id, count(*) as dupes
FROM organizations
GROUP BY orgName, id
HAVING count(*) > 1;
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.