SQL Server'da yinelenen satırları bulma


231

Kuruluşların bir SQL Server veritabanı var ve birçok yinelenen satır var. Tüm bunları ve dupes miktarını kapmak için bir select deyimi çalıştırmak istiyorum, aynı zamanda her kuruluş ile ilişkili kimlikleri döndürmek istiyorum.

Şunun gibi bir ifade:

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

Gibi bir şey döndürecek

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

Ama aynı zamanda onların kimliklerini de almak istiyorum. Bunu yapmanın bir yolu var mı? Belki bir

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

Bunun nedeni, bu kuruluşlara bağlanan ayrı bir kullanıcı tablosu olması ve onları birleştirmek istiyorum (bu nedenle, dupupe'leri kaldırın, böylece kullanıcılar dupe orgs yerine aynı kuruluşa bağlanır). Ama elle bir parça istiyorum, bu yüzden hiçbir şey berbat değilim, ama yine de tüm dupe orgs kimlikleri dönen bir ifade gerekir, böylece kullanıcılar listesi üzerinden gidebilirsiniz.

Yanıtlar:


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
bu sorguda herhangi bir sınırlama var mı, örneğin kayıt sayısı 10 milyon artı ise?
Steam

3
@Steam Haklısınız: Bu cevap milyonlarca kayıt içeren daha büyük bir veritabanında verimli değildir. Veritabanı tarafından daha iyi optimize edilebilen Aykut tarafından gönderilen GroupBy / yanıtını tercih edin. Bir istisna: İşleri basitleştirmek için Count (*) yerine Count (0) kullanmanızı öneririm.
Mike Christian

1
@Mike - neden Count (0) vs Count (*)?
KornMuffin

2
@KornMuffin Geriye dönük olarak, Count () hakkındaki yorumum geçersiz. Count () içinde null olmayan bir değerlendirme kullanmak yalnızca bir dış birleştirme tarafından döndürülen null olmayan sonuçları saymak istediğinizde kullanışlıdır. Aksi takdirde, Sayı (*) kullanın. Burada harika bir açıklama var .
Mike Christian

bölümünde isnull()null olabilecek sütunlar için kullanmaon
Arif Ulusoy

92

Aşağıdaki sorguyu çalıştırabilir max(id)ve bu satırlarla yinelenenleri bulabilir ve silebilirsiniz.

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

Ancak bu sorguyu birkaç kez çalıştırmanız gerekir.


Tam olarak çalıştırmak zorundasınız MAX( COUNT(*) ) - 1, ki bu hala mümkün olabilir.
DerMike

1
merhaba onların 2 için max id yerine tüm kimliği almak için herhangi bir yoludur ben max ve min kullanabilirsiniz ama 2'den fazla ne olacak? @DerMike
Arijit Mukherjee

31

Bunu şu şekilde yapabilirsiniz:

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

Yalnızca silinebilecek kayıtları (her birinden bir tanesini bırakarak) döndürmek istiyorsanız, aşağıdakileri kullanabilirsiniz:

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

Düzenleme: SQL Server 2000, ROW_NUMBER () işlevine sahip değil. Bunun yerine şunları kullanabilirsiniz:

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

İlk ifade işe yarıyor ama ikincisi işe yaramıyor.
Ocak'ta xtine

SQL Server row_number () tanıyamıyor gibi görünüyor?
Ocak'ta xtine

Ah ... SQL Server'ın eski bir sürümü var mı? SQL Server 2005'te tanıtıldığına inanıyorum.
Paul

3
Tekrar teşekkürler, bunu yapmak istediğim her zaman buraya
geliyorum

9

Doğru olarak işaretlenmiş çözüm benim için işe yaramadı, ancak çok iyi çalışan bu cevabı buldum: MySql'de yinelenen satırların listesini alın

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

Sonuç kümesinde çok sayıda tekrar elde edersiniz, böylece bunlarla da uğraşmanız gerekir.
Renan

1
Kimlik sayısal ise, kontrol n1.id > n2.idher çiftin iki kez görünmesini engeller.
16:19, starwed

9

Bunu deneyebilirsin, senin için en iyisi

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

virgül bölünmüş veya farklı sütunlardaki tüm kimliği almanın herhangi bir yolu
Arijit Mukherjee

6

Kopyaları silmek istiyorsanız:

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]

Yinelenen Kayıt bulmak için 1) CTE kullanma

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 Kullanarak

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

Bu, en hızlı çözüm, 10m'den fazla satırdan veri seçerken. Teşekkürler
Fandango68

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

Bu nedenle, rowum> 1 olan kayıtlar tablonuzdaki yinelenen kayıtlar olacaktır. 'Bölümleme ölçütü' ilk kayıtlara göre gruplandırın ve seri numaralarını vererek bunları serileştirin. Dolayısıyla rownum> 1, bu şekilde silinebilecek yinelenen kayıtlar olacaktır.


Bunu sevdim çünkü iç seçim cümleciklerine kolayca daha fazla sütun eklemenize izin veriyor. Dolayısıyla, "Kuruluşlar" tablosundan diğer sütunları döndürmek istiyorsanız, bu sütunlarda bir "gruplama" işlemi yapmanız gerekmez.
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

Seçmek için birkaç yolunuz var duplicate rows.

çözümlerim için önce bu tabloyu düşünün

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

İlk çözüm:

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

Secound çözümü: Kullanım identityalanı

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

ve tüm çözümlerin sonunda bu komutu kullanın

DROP TABLE #Employee

0

sanırım cevaplar arasında karıştırmak için neye ihtiyacım olduğunu biliyorum ve ben istediğini çözümü var düşünüyorum:

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

maksimum kimliğe sahip olmak size cumhuriyetin kimliğini ve istediği orijinalin kimliğini verecektir:

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)

Bu formda ortaya koyduğunuz sadece üzücü bir şey

id , name , dubid , name

umarım hala yardımcı olur


0

'Öğrenci' tablosunu 2 sütunlu bir tablonuz olduğunu varsayalım:

  • student_id int
  • student_name varchar

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

Şimdi yinelenen kayıtları görmek istiyoruz Bu sorguyu kullanın:

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

Bir tablodaki yinelenen kayıtları almak için daha iyi bir seçenek var

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

Yukarıdaki sorgunun sonucu, benzersiz öğrenci kimliğine sahip tüm yinelenen adları ve yinelenen yineleme sayısını gösterir

Sql sonucunu görmek için buraya tıklayın


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

Yinelenen satırları bulmak için iki yöntem kullanıyorum. 1. yöntem gruba sahip ve sahip olan en ünlü yöntemdir. 2. yöntem CTE - Ortak Tablo İfadesi kullanmaktır .

@RedFilter tarafından belirtildiği gibi bu yol da doğrudur. Çoğu zaman CTE yönteminin benim için de yararlı olduğunu düşünüyorum.

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

Yukarıdaki örnekte sonucu ROW_NUMBER ve PARTITION BY kullanarak tekrar oluşumunu bularak topladık. Daha sonra yalnızca tekrarlanan satırları 1'den fazla olan sayıları seçmek için where yan tümcesini uyguladık. Tüm sonuç CTE tablosu toplanır ve Organizasyonlar tablosuyla birleştirilir.

Kaynak: CodoBee


-2

Deneyin

SELECT orgName, id, count(*) as dupes
FROM organizations
GROUP BY orgName, id
HAVING count(*) > 1;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.