SQL tablosunda yinelenen değerler bulma


1935

Bir alanla yinelenenleri bulmak kolaydır:

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

Yani bir masamız varsa

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

Bu sorgu bize John, Sam, Tom, Tom verecek, çünkü hepsi aynı email.

Ancak, istediğim aynı email ve ile çoğaltmalar elde etmektir name.

Yani, "Tom", "Tom" almak istiyorum.

Buna ihtiyacımın nedeni: Bir hata yaptım ve yinelenen nameve emaildeğerler eklemeye izin verdim . Şimdi kopyaları kaldırmam / değiştirmem gerekiyor, bu yüzden önce onları bulmam gerekiyor.


28
Toplama işlevinde olmadığı için ilk örneğinizde ad seçmenize izin vereceğini sanmıyorum. "Eşleşen e-posta adresleri ve adlarının sayısı nedir?" Bazı zor mantık ...
sXe

3
nameSELECT alanından dolayı bunun MSSQL sunucusuyla çalışmadığı bulundu .
E. van Putten

ihtiyacım olan yinelenen e-posta ile kayıtların kimliği
Marcos Di Paolo

Yanıtlar:


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

Her iki sütunu da gruplandırın.

Not: eski ANSI standardı, GROUP BY'da birleştirilmiş olmayan tüm sütunlara sahip olmakla birlikte, bu "işlevsel bağımlılık" fikriyle değişmiştir :

İlişkisel veritabanı teorisinde, işlevsel bir bağımlılık, bir veritabanından bir ilişkide iki öznitelik kümesi arasındaki bir kısıtlamadır. Başka bir deyişle, işlevsel bağımlılık, bir ilişkideki öznitelikler arasındaki ilişkiyi tanımlayan bir kısıtlamadır.

Destek tutarlı değil:


92
@webXL NEREDE tek kayıt ile çalışıyor HAVING grupla çalışıyor
bjan

8
@gbn Kimliği sonuçlara dahil etmek mümkün mü? Daha sonra bu kopyaları silmek daha kolay olacaktır.
user797717

13
@ user797717: MIN (ID) değerine sahip olmanız ve daha sonra MIN (ID) değerleri değilse son olmayan kimlik değerleri için silmeniz gerekir
gbn

1
Sütunlardan herhangi birinin null değerlere sahip olduğu durumlar ne olacak?
Ankit Dhingra

1
Bunun için çok teşekkürler ve evet, durumun benzersizliğine ihtiyacım olsa da, Oracle'da çalışıyor>1 =1
Bill Naylor

370

bunu dene:

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

ÇIKTI:

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

(2 row(s) affected)

dups kimlikleri istiyorsanız bunu kullanın:

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

ÇIKTI:

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

(4 row(s) affected)

kopyaları silmek için şunu deneyin:

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

ÇIKTI:

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

(4 row(s) affected)


72

Yinelenenleri silmek istiyorsanız, bunu üçlü bir alt seçime çift / tek satır bulmak zorunda kalmanın çok daha basit bir yolu var:

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

Ve böylece silmek için:

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
)

IMHO'yu okumak ve anlamak çok daha kolay

Not: Tek sorun, silinen hiçbir satır kalmayana kadar isteği yürütmeniz gerektiğidir, çünkü her seferinde her yinelenen dosyadan yalnızca birini silersiniz


2
Güzel ve okunması kolay; Gerçi tek seferde birden çok yinelenen satırı silen bir yol bulmak istiyorum.
Dickon Reed

1
Bu benim için işe yaramıyorYou can't specify target table 'users' for update in FROM clause
Whitecat

1
@Whitecat basit bir MySQL sorunu gibi görünüyor: stackoverflow.com/questions/4429319/…
AncAinu

1
Benim için başarısız. "DBD :: CSV :: st yürütme başarısız oldu: /Users/hornenj/perl5/perlbrew/perls/perl-5.26.0/lib/site_perl/5.26 hash öğesinde başlatılmamış $ $ [1] kullanımı. 0 / SQL / Eval.pm line 43 "
Nigel Horne

1
Bence nerede "u.name = u2.name AND u.email = u2.email AND (u.id> u2.id VEYA u2.id> u.id)" değil mi?
GiveEmTheBoot

48

Takip etmeyi dene:

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 * 'deki küçük bir değişiklik, bir saatlik aramayı çözmeme yardımcı oldu. Daha önce TARAFINDAN AŞIRI (bölme hiç kullanmamış ben hayret edilecek hiç bitmeyecek kaç SQL aynı şeyi yapmak için yollar.!
Joe Ruder

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

28

Partiye biraz geç ama tüm yinelenen kimlikleri bulmak için gerçekten harika bir çözüm buldum:

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

2
Sözdizimsel bir şeker işi olduğu anlaşılıyor. Güzel bulmak.
Chef_Code

3
GROUP_CONCATÖnceden belirlenmiş bir uzunluktan sonra duracağını unutmayın , böylece tüm s'leri alamayabilirsiniz id.
v010dya

24

bu kodu dene

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

Bu, her yinelenen gruptan bir kayıt hariç tüm yinelenen kayıtları seçer / siler. Bu nedenle, silme tüm benzersiz kayıtları + kopyaların her grubundan bir kayıt bırakır.

Kopyaları seçin:

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

Kopyaları sil:

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

Daha büyük kayıtların farkında olun, performans sorunlarına neden olabilir.


2
Sorgu silme hatası - FROM yan tümcesinde güncelleme için 'şehirler' hedef tablosunu belirleyemezsiniz
Ali Azhar

2
Ne tablo 'şehirler' ne de güncelleme maddesi yoktur. Ne demek istiyorsun? Silme sorgusunda bir hata nerede?
Martin Silovský

2
Bu OP'nin verileriyle nasıl çalışır?
thoroc

3
"OP" ne anlama geliyor?
Martin Silovský

19

Oracle ile çalışmanız durumunda bu yol tercih edilir:

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
Yığın Taşması'nda yalnızca kod yanıtları kaşlarını çattı, bunun neden soruyu cevapladığını açıklayabilir misiniz?
Rich Benner

2
@RichBenner: Sonuçtaki her satır ve hangilerinin hepsinin yinelenen satırlar olduğunu ve hangilerinin bir bakışta olmadığını ve gruplandırılmamasını söyleyen yanıtı bulamadım, çünkü bunu birleştirmek istiyorsak tarafından başka bir sorgu grubu ile sorgu iyi bir seçenek değildir.
Narendra

2
Select deyimine Id eklemek ve çoğaltılanlara filtre uygulamak, size çoğaltılan kimlikleri silme ve her birini koruma imkanı verir.
Antoine Reinhold Bertrand

12

Tablonuzda yinelenen satır olup olmadığını görmek istiyorsanız, Sorgu altında kullandım:

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

Ortaya koyduğum kolay şey bu. Ortak bir tablo ifadesi (CTE) ve bir bölüm penceresi kullanır (Ben bu özellikleri SQL 2008 ve sonrası olduğunu düşünüyorum).

Bu örnek, yinelenen ad ve dob'a sahip tüm öğrencileri bulur. Çoğaltmayı denetlemek istediğiniz alanlar OVER yan tümcesinde bulunur. Yansıtmaya istediğiniz diğer alanları ekleyebilirsiniz.

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

Yinelenen değerleri nasıl sayabiliriz? ya 2'den fazla ya da 2'den daha fazla tekrarlanır.

kadar basit

select COUNT(distinct col_01) from Table_01

2
Bu, sorulduğu gibi soru için nasıl çalışır? Bu mu değil satırları vermek birden çok sütun yinelenen bilgiler farklı satırlarda (örneğin, "e-posta" ve "name").
Jeroen

10

CTE kullanarak da bunun gibi yinelenen değerler bulabiliriz

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;

Bu belirli bir sütunda tekrarlanan değerleri aramak için düzgün çalışacağını düşünüyorum.


6
Bu, en üstteki cevaba pek bir şey eklemez ve teknik olarak OP'nin soruda yayınlanan kodundan gerçekten farklı değildir.
Jeroen

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

6

Bu da işe yaramalı, belki denemelisiniz.

  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)

Özellikle sizin durumunuz için iyi Eğer bir tür ön eki veya postadaki yeni alan adı gibi genel değişikliği olan kopyaları ararsanız. bu sütunlarda replace () yöntemini kullanabilirsiniz


5

Yinelenen verileri (bir veya birkaç ölçütle) bulmak ve gerçek satırları seçmek istiyorsanız.

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)

Sen kullanamazsınız COUNTolmadan GROUP BYbu bütün tabloya atıfta sürece,.
RalfFriedl

Grup olmadan COUNT kullandınız ama burada COUNT yazmak için yazarak hata yapıyorum
Mohammad Neamul Islam

3

İsimleri kopya olan kayıtları silmek için

;WITH CTE AS    
(

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

DELETE FROM CTE WHERE T > 1

3

Kontrol etmek için Yinelenen bir tabloya kaydedin.

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

veya

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

Tablodaki yinelenen kaydı silmek için.

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

veya

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

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


1

Burada, aşağıda gösterildiği gibi toplama işlevleri üzerinde çalışanlara sahip olabiliriz

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

Burada iki alan id_account ve veri Count (*) ile kullanılır. Böylece, her iki sütunda birden fazla aynı değere sahip tüm kayıtları verecektir.

SQL Server tablosuna herhangi bir kısıtlama eklemeyi kaçırmış olmamızın bir nedeni var ve kayıtlar ön uç uygulamasıyla tüm sütunlara yinelenmiştir. Sonra yinelenen sorguyu tablodan silmek için aşağıdaki sorguyu kullanabiliriz.

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

Burada orignal tablonun tüm ayrı kayıtlarını aldık ve orijinal tablonun kayıtlarını sildik. Yine yeni tablodan özgün tabloya tüm farklı değerleri ekledik ve sonra yeni tabloyu sildik.


1

Bunu denemek isteyebilirsiniz

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

1

Buradaki en önemli şey, en hızlı işleve sahip olmaktır. Ayrıca kopya endeksleri de tanımlanmalıdır. Kendi kendine birleştirme iyi bir seçenektir, ancak daha hızlı bir işleve sahip olmak için önce kopyaları olan satırları bulmak ve daha sonra çoğaltılan satırların kimliğini bulmak için orijinal tabloya katılmak daha iyidir. Son olarak id dışında herhangi bir sütuna göre sıralı satırlar olmasını isteyin.

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

Yinelemelerden kurtulmak için SELECT DISTINCT anahtar sözcüğünü kullanabilirsiniz. Ayrıca ada göre filtreleyebilir ve bu ada sahip herkesi bir masaya alabilirsiniz.


0

Tam kod, yinelenen satırları mı yoksa yalnızca aynı e-posta ve ada sahip farklı kimlikleri mi bulmak istediğinize bağlı olarak değişir. İd birincil anahtarsa ​​veya benzersiz bir kısıtlamaya sahipse bu ayrım yoktur, ancak soru bunu belirtmez. Önceki durumda, diğer birkaç cevapta verilen kodu kullanabilirsiniz:

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

İkinci durumda şunları kullanırsınız:

SELECT name, email, COUNT(DISTINCT id)
FROM users
GROUP BY name, email
HAVING COUNT(DISTINCT id) > 1
ORDER BY COUNT(DISTINCT id) DESC
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.