MySQL'de yinelenen değerler bulma


769

Bir varchar sütun içeren bir tablo var ve bu sütunda yinelenen değerleri olan tüm kayıtları bulmak istiyorum. Yinelenenleri bulmak için kullanabileceğim en iyi sorgu nedir?


1
Tüm kayıtları bulmanızdan bahsettiğinizden, bu varchar sütununda KEYS'i ve yinelenen DEĞERLERİ bilmeniz gerektiğini varsayıyorum.
TechTravelThink

Değerleri aldıktan sonra anahtarları yeterince kolay bulabilirim, gerçekten tüm yinelenen değerlerin bir listesini istiyorum.
Jon Tackabury

Yanıtlar:


1522

Bir Do SELECTa ile GROUP BYmaddede. Diyelim ki ad , kopyalarını bulmak istediğiniz sütundur:

SELECT name, COUNT(*) c FROM table GROUP BY name HAVING c > 1;

Bu , ilk sütundaki ad değeri ve ikincisinde bu değerin kaç kez göründüğü ile ilgili bir sonuç döndürür .


27
Ancak yinelenen değerlere sahip satırların kimliklerini alamıyorsanız bu nasıl yararlı olur? Evet, her yinelenen değer için yeni bir sorgu eşleştirmesi yapabilirsiniz, ancak yinelenenleri listelemek mümkün mü?
NobleUplift

23
@NobleUplift Bir yapabilirsiniz GROUP_CONCAT(id)ve kimlikleri listeleyecektir. Bir örnek için cevabımı görün.
Matt Rardon

5
Söylese ne demek olurdu ERROR: column "c" does not exist LINE 1?
Kullanıcı

15
Bunun neden kabul edilen cevap olduğu ve neden bu kadar çok oyu olduğunu karıştırıyorum. OP sordu, "Ben bu sütunda yinelenen değerleri olan tüm kayıtları bulmak istiyorum." Bu cevap bir sayım tablosu döndürür. -1
Monica Heddneck

4
HAVING'in nasıl çalıştığını anlamayanlar için - sadece sonuç kümesindeki bir filtre, ana sorgudan sonra olur.
John Hunt

236
SELECT varchar_col
FROM table
GROUP BY varchar_col
HAVING COUNT(*) > 1;

10
Fazladan sütun eklemediğinden @ levik'in cevabından daha üstündür. İle kullanmak için kullanışlı yapar IN()/ ' NOT IN().
wmassingham

172
SELECT  *
FROM    mytable mto
WHERE   EXISTS
        (
        SELECT  1
        FROM    mytable mti
        WHERE   mti.varchar_column = mto.varchar_column
        LIMIT 1, 1
        )

Bu sorgu sadece farklı değil, tam kayıtları döndürür varchar_column.

Bu sorgu kullanılmıyor COUNT(*). Çok sayıda yinelenen varsa COUNT(*), pahalıdır ve bütüne COUNT(*)ihtiyacınız yoksa, aynı değere sahip iki satır olup olmadığını bilmeniz gerekir.

varchar_columnTabii ki, bir dizin olması bu sorguyu büyük ölçüde hızlandıracaktır.


3
Çok iyi. ORDER BY varchar_column DESCSorgunun sonuna ekledim .
trant

8
Bu, kabul edilen cevap olarak gerektiği GROUP BYve HAVINGolası kopyaların tek döner. Ayrıca, yerine dizinli alan ile performans COUNT(*)ve ORDER BYyinelenen kayıtları gruplandırma imkanı .
Rémi Breton

1
Yukarıdaki yorumlarda belirtildiği gibi, bu sorgu tüm yinelenen satırları listelemenizi sağlar. Çok kullanışlı.
TryHarder

4
Buna baktığımda nasıl çalışacağını anlamıyorum. Dış tablonun herhangi bir satırı iç tablonun içinde de mevcut olacağından ve her sıranın her zaman en azından kendisiyle eşleşeceğinden iç koşul her zaman doğru olmaz mı? Sorguyu denedim ve şüphelendiğim sonucu aldım - her satır döndü. Ama bu kadar çok oyla kendimden şüphe ediyorum. İç sorguda "AND mto.id <> mti.id" gibi bir şey eksik değil mi? Bunu eklediğimde benim için işe yarıyor.
Clox,

2
@Quassnoi Tamam. Ben sqlfiddle koyarak denedim ama şema oluşturmak dışında çalıştırmak için çalıştığım her sorgu zaman aşımına uğradı beri vazgeçtim. Ben sadece "EXISTS" kaldırmanın da sorgu benim için düzgün çalışmasını sağlar anladım.
Clox

144

Yinelenen satırların kimliklerini almak için levik yanıtından yola çıkarak GROUP_CONCAT, sunucunuz destekliyorsa yapabilirsiniz (bu, virgülle ayrılmış kimlik listesi döndürür).

SELECT GROUP_CONCAT(id), name, COUNT(*) c FROM documents GROUP BY name HAVING c > 1;

12
Bunca zaman GROUP_CONCAT () hakkında bilgi sahibi olmadan! çok çok faydalı.
aesede

Gerçekten takdir Matt. Bu gerçekten faydalı! Kimliğini böyle bir işlevle birlikte bırakırsanız phpmyadmin'de güncelleme yapmaya çalışanlar için: SELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...]satır içi düzenlemeyi etkinleştirir ve ilgili tüm satırları (veya en azından ilk eşleşen) güncellemelidir, ancak maalesef düzenleme bir Javascript hatası oluşturur. ..
Armfoot

Daha sonra kaç kimliğin kopyalamaya tabi olduğunu nasıl hesaplarsınız?
CMCDragonkai

2
Nasıl tüm kimlikleri gruplandırmak değil, ilk yerine son listelenir; ilgili tüm değerleri yanlarındaki sütunlarda? Bu yüzden gruplamak yerine, sadece ID 1 ve değerini, ID 2 ve değerini gösterir. Kimlik değerleri aynı ise EVEN.
MailBlade

1
Son derece yararlı bir cevap, daha fazla insanın görmesi için bu en üstte olmalı. Bu tür listeleri oluştururken ne kadar acı çektiğimi hatırlıyorum ve her zaman komut olarak mevcuttu ..
John

13

Tablonuzun TableABC olduğunu ve istediğiniz sütunun Col ve T1'in birincil anahtarının Anahtar olduğunu varsayarsak.

SELECT a.Key, b.Key, a.Col 
FROM TableABC a, TableABC b
WHERE a.Col = b.Col 
AND a.Key <> b.Key

Bu yaklaşımın yukarıdaki cevaba göre avantajı, Anahtarı vermesidir.


4
+1 Çünkü kullanışlı. İronik olarak, sonucun kendisi kopyalar içeriyor (a ve b, sonra b ve a
listeliyor

2
@FabienSnauwaert Yinelenenlerin bazılarından daha az (veya daha büyük) karşılaştırarak kurtulabilirsiniz
Michael

Cevabınızı çok net düşünün, bunun için teşekkürler, ancak büyük masada biraz zaman alır (daha fazla 20.000 giriş tablosunda yaklaşık 2mn) ve 25 ilk sonucu gösterdikten sonra, bir sonrakini göstermek için tıklatırsam phpmyadmin show error "# 1052 - Sipariş fıkrasında 'id' sütunu belirsiz "
bcag2

12
SELECT * 
FROM `dps` 
WHERE pid IN (SELECT pid FROM `dps` GROUP BY pid HAVING COUNT(pid)>1)

1
Hayır, çünkü bu muhtemelen en yavaş olanı. Alt seçimler, döndürülen her satır için yürütüldükleri için kötü bir şekilde yavaştır.
Oddman

10

Çalışan adı sütununda kaç kaydın yinelenen olduğunu bulmak için aşağıdaki sorgu yardımcı olur;

Select name from employee group by name having count(*)>1;

10

çoğaltma içeren tüm verileri almak için ben bu kullanılır:

SELECT * FROM TableName INNER JOIN(
  SELECT DupliactedData FROM TableName GROUP BY DupliactedData HAVING COUNT(DupliactedData) > 1 order by DupliactedData)
  temp ON TableName.DupliactedData = temp.DupliactedData;

TableName = birlikte çalıştığınız tablo.

DupliactedData = aradığınız yinelenen veriler.


Bu, her bir kopyayı kendi satırında gösterir. Buna ihtiyacım var. Teşekkürler.
warmwhisky

8

Son sorgum, gruplara göre gruplama, GROUP_CONCAT sayısını birleştirmek için burada yardımcı olan birkaç cevabı içeriyordu.

SELECT GROUP_CONCAT(id), `magento_simple`, COUNT(*) c 
FROM product_variant 
GROUP BY `magento_simple` HAVING c > 1;

Bu, her iki örneğin de kimliğini (virgülle ayrılmış), ihtiyacım olan barkodu ve kaç kopya olduğunu gösterir.

Tabloyu ve sütunları uygun şekilde değiştirin.


8

Çoğaltmalar açısından birçok kullanımı olan herhangi bir JOIN yaklaşımı görmüyorum.

Bu yaklaşım size gerçek iki katına çıkmış sonuçlar verir.

SELECT t1.* FROM my_table as t1 
LEFT JOIN my_table as t2 
ON t1.name=t2.name and t1.id!=t2.id 
WHERE t2.id IS NOT NULL 
ORDER BY t1.name

2
FYI - 1'den fazla yinelenen kaydın bulunma potansiyeli varsa, 'farklı bir sütun seçmeniz' istenecektir. Aksi takdirde, sonuçlar bulunan yinelenen satırların kopyalarını içerecektir.
Drew

7
SELECT t.*,(select count(*) from city as tt
  where tt.name=t.name) as count
  FROM `city` as t
  where (
     select count(*) from city as tt
     where tt.name=t.name
  ) > 1 order by count desc

Şehri Masanızla değiştirin . Adı alan adınızla değiştirin



6

Yukarıdaki sonucu gördüm ve yinelenen tek sütun değerini kontrol etmeniz gerekiyorsa sorgu iyi çalışır. Örneğin e-posta.

Ancak daha fazla sütunla kontrol etmeniz gerekiyorsa ve bu sorgunun iyi çalışabilmesi için sonucun kombinasyonunu kontrol etmek istiyorsanız:

SELECT COUNT(CONCAT(name,email)) AS tot,
       name,
       email
FROM users
GROUP BY CONCAT(name,email)
HAVING tot>1 (This query will SHOW the USER list which ARE greater THAN 1
              AND also COUNT)

Tam olarak ne gerekiyordu! İşte benim sorgu, kopyaları için 3 alanları kontrol:SELECT COUNT(CONCAT(userid,event,datetime)) AS total, userid, event, datetime FROM mytable GROUP BY CONCAT(userid, event, datetime ) HAVING total>1
Kai Noack

4

Ben tüm satır görebiliyordu çünkü çoğaltmaları bulmak için pencereli işlevleri (MySQL 8.0+) kullanmayı tercih ederim:

WITH cte AS (
  SELECT *
    ,COUNT(*) OVER(PARTITION BY col_name) AS num_of_duplicates_group
    ,ROW_NUMBER() OVER(PARTITION BY col_name ORDER BY col_name2) AS pos_in_group
  FROM table
)
SELECT *
FROM cte
WHERE num_of_duplicates_group > 1;

DB Fiddle Demosu


3
SELECT 
    t.*,
    (SELECT COUNT(*) FROM city AS tt WHERE tt.name=t.name) AS count 
FROM `city` AS t 
WHERE 
    (SELECT count(*) FROM city AS tt WHERE tt.name=t.name) > 1 ORDER BY count DESC

1
Aynı alt sorguyu iki kez yapmak verimsiz görünüyor.
NobleUplift


3
CREATE TABLE tbl_master
    (`id` int, `email` varchar(15));

INSERT INTO tbl_master
    (`id`, `email`) VALUES
    (1, 'test1@gmail.com'),
    (2, 'test2@gmail.com'),
    (3, 'test1@gmail.com'),
    (4, 'test2@gmail.com'),
    (5, 'test5@gmail.com');

QUERY : SELECT id, email FROM tbl_master
WHERE email IN (SELECT email FROM tbl_master GROUP BY email HAVING COUNT(id) > 1)

2
SELECT DISTINCT a.email FROM `users` a LEFT JOIN `users` b ON a.email = b.email WHERE a.id != b.id;

1
Sorgulanan sütun dizine eklenmezse, bunun dayanılmaz derecede yavaş olduğunu veya bitmeyebileceğini belirtmek gerekir. Aksi takdirde, değiştirmek başardı a.emailiçin a.*ve tekrarlar da tüm satırları kimliklerini olsun.
NobleUplift

@NobleUplift Neden bahsediyorsun?
Michael

@Michael Bu üç yaşından beri kullandığım MySQL sürümünü test edemiyorum, ancak aynı sorguyu seçtiğim sütunun üzerinde bir dizin olmadığı bir veritabanında denedim, bu yüzden oldukça bitirmek için birkaç saniye. Bunu değiştirmek SELECT DISTINCT a.*neredeyse anında çözüldü.
NobleUplift

@NobleUplift Ah tamam. Yavaş olduğunu anlayabiliyorum ... endişelendiğim kısım “bitmeyebilir”.
Michael

@Michael Bu sorguyu sistemimizde hangi tablo üzerinde çalıştırmak zorunda olduğumu hatırlamıyorum, ancak birkaç milyon kaydı olanlar için muhtemelen bitireceklerdi, ancak o kadar uzun sürdü ki, aslında bitirirdi.
NobleUplift

1

Birden çok alana sahip yinelenen satırları kaldırmak için, önce bunları yalnızca farklı satırlar için belirtilen yeni benzersiz anahtara yönlendirin, ardından aynı yeni benzersiz anahtarla yinelenen satırları kaldırmak için "gruplama" komutunu kullanın:

Create TEMPORARY table tmp select concat(f1,f2) as cfs,t1.* from mytable as t1;
Create index x_tmp_cfs on tmp(cfs);
Create table unduptable select f1,f2,... from tmp group by cfs;

bir açıklama da ekleyebilir misiniz?
Robert

Neden kullanmıyorsunuz CREATE TEMPORARY TABLE ...? Çözümünüzün küçük bir açıklaması harika olurdu.
maxhb

1

Çok geç bir katkı ... herkesin hattan aşağı inmesine yardımcı olması durumunda ... Bir bankacılık uygulamasında eşleşen işlemleri çiftlerini (aslında hesaptan hesaba transferlerin her iki tarafı) bulmak, hangilerini belirlemek için bir görevim vardı her hesaplar arası aktarım işlemi için 'from' ve 'to' idi, bu yüzden bununla sonuçlandık:

SELECT 
    LEAST(primaryid, secondaryid) AS transactionid1,
    GREATEST(primaryid, secondaryid) AS transactionid2
FROM (
    SELECT table1.transactionid AS primaryid, 
        table2.transactionid AS secondaryid
    FROM financial_transactions table1
    INNER JOIN financial_transactions table2 
    ON table1.accountid = table2.accountid
    AND table1.transactionid <> table2.transactionid 
    AND table1.transactiondate = table2.transactiondate
    AND table1.sourceref = table2.destinationref
    AND table1.amount = (0 - table2.amount)
) AS DuplicateResultsTable
GROUP BY transactionid1
ORDER BY transactionid1;

Sonuç olarak, DuplicateResultsTableeşleşen (yani yinelenen) işlemleri içeren satırlar sağlanır, ancak aynı çiftle ikinci kez eşleştiğinde tersine aynı işlem kimlikleri sağlanır, böylece dış SELECT, yapılan ilk işlem kimliğine göre gruplandırılır. kullanarak LEASTve GREATESTemin iki transactionId en için güvenli kılar sonuçlarında aynı sırada, her zaman yapmak GROUPböylece tüm yinelenen eşleşmeleri eleyecek, ilkine göre. Yaklaşık bir milyon kayıttan geçti ve 2 saniyenin altında 12.000'den fazla maç belirledi. Tabii işlem kimliği gerçekten yardımcı olan birincil endekstir.


1
Select column_name, column_name1,column_name2, count(1) as temp from table_name group by column_name having temp > 1

1
SELECT ColumnA, COUNT( * )
FROM Table
GROUP BY ColumnA
HAVING COUNT( * ) > 1

3
Bu, benzersiz oluşumlar da bulduğu için yanlıştır. 0 1 olmalıdır.
Kafoso

1

Yinelenen kullanımı kaldırmak istiyorsanız DISTINCT

Aksi takdirde bu sorguyu kullanın:

SELECT users.*,COUNT(user_ID) as user FROM users GROUP BY user_name HAVING user > 1;


0

Bu sorguyu kullanmayı deneyin:

SELECT name, COUNT(*) value_count FROM company_master GROUP BY name HAVING value_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.