MySQLで重複する値を見つける


769

varchar列のあるテーブルがあり、この列に重複する値を持つすべてのレコードを検索したいと思います。重複を見つけるために使用できる最良のクエリは何ですか?


1
あなたはすべてのレコードを見つけると述べたので、そのvarchar列のKEYSと重複したVALUESを知っている必要があると想定しています。
TechTravelThink 2009年

値を取得した後でキーを簡単に見つけることができます。実際には、重複するすべての値のリストが必要です。
Jon Tackabury、2009年

回答:


1522

やるSELECTGROUP BY句。名前が重複を検索したい列であるとしましょう:

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

これにより、最初の列に名前の値を含む結果が返され、その値が2番目の列に出現した回数が返されます。


27
しかし、重複する値を持つ行のIDを取得できない場合、これはどのように役立ちますか?はい、重複する値ごとに新しいクエリ照合を実行できますが、重複を一覧表示することは単に可能ですか?
NobleUplift 2014

23
@NobleUpliftを実行するGROUP_CONCAT(id)と、IDがリストされます。例については、私の回答を参照してください。
Matt Rardon、2015

5
それが言ったらどういう意味ERROR: column "c" does not exist LINE 1ですか?
ユーザー

15
なぜこれが受け入れられた回答であり、なぜそれが非常に多くの賛成票を持っているのか混乱しています。OPは、「この列に重複する値を持つすべてのレコードを検索したい」と尋ねました。この回答は、カウントのテーブルを返します。-1
モニカヘドネック2017

4
HAVINGがどのように機能するかを理解していない人のために-これは単に結果セットのフィルターなので、メインのクエリの後に発生します。
ジョンハント

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

10
余分な列が追加されないため、@ levikの回答よりも優れています。IN()/ と一緒に使用すると便利ですNOT IN()
wmassingham 2015年

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

このクエリは、個別varchar_columnのレコードだけでなく、完全なレコードを返します。

このクエリはを使用しませんCOUNT(*)。重複が多数あり、COUNT(*)コストが高く、全体を必要としない場合はCOUNT(*)、同じ値の行が2つあるかどうかを確認するだけです。

varchar_columnもちろん、意志にインデックスがあると、このクエリが大幅に高速化されます。


3
とても良い。ORDER BY varchar_column DESCクエリの最後に追加しました。
トランテ2014年

8
これは、可能な重複の1つだけGROUP BYHAVING返すので、受け入れられた答えである必要があります。また、の代わりにインデックス付きフィールドを使用したパフォーマンスCOUNT(*)、およびORDER BY重複レコードをグループ化する可能性。
レミブルトン

1
上記のコメントで述べたように、このクエリを使用すると、重複するすべての行を一覧表示できます。非常に便利。
TryHarder 2016

4
これを見て、私はそれがどのように機能するのか全く理解できません。外部テーブルの行も内部テーブルで使用できるため、すべての行が常に少なくともそれ自体と一致するため、内部条件は常にtrueになりますか?私はクエリを試して、疑わしい結果を得ました-すべての行が返されました。しかし、非常に多くの賛成票があるので、私は自分自身を疑っています。内部クエリに「AND mto.id <> mti.id」のようなものが欠けていませんか?追加するとうまくいきます。
Clox

2
@Quassnoiよし。私はそれをsqlfiddleに配置しようとしましたが、スキーマの作成を除いて、実行しようとするすべてのクエリがタイムアウトになるため、あきらめました。「EXISTS」を削除するだけでもクエリが正しく機能することがわかりました。
Clox

144

重複する行のIDを取得するためのlevikの回答を基にしてGROUP_CONCAT、サーバーがサポートしている場合に実行できます(これにより、IDのコンマ区切りのリストが返されます)。

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

12
今まではGROUP_CONCAT()について知らずに!とても便利です。
aesede

マットに本当に感謝しています。これは本当に役に立ちます!次のような関数と一緒にidを残した場合にphpmyadminで更新しようとするSELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...]と、インライン編集が有効になり、関係するすべての行(または少なくとも最初に一致した行)が更新されますが、残念ながら編集によりJavaScriptエラーが生成されます。 ..
アームフット

次に、重複するIDの数をどのように計算しますか?
CMCDragonkai 2017年

2
すべてのIDをグループ化せずに、最初から最後までリストするにはどうすればよいですか。それらの隣の列にすべてのそれぞれの値を使用して?したがって、グループ化する代わりに、ID 1とその値、ID 2とその値を表示するだけです。IDの値が同じ場合。
MailBlade

1
非常に役立つ回答です。これは一番上に表示されるので、より多くの人が見ることができます。そのようなリストを作成するのに苦労したことを覚えており、コマンドとしていつでも利用可能でした..
John

13

テーブルの名前がTableABCで、必要な列がColで、T1の主キーがKeyであるとします。

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

上記の回答に対するこのアプローチの利点は、キーを提供することです。


4
+1便利だから。皮肉なことに、結果自体には重複が含まれています(aとb、次にbとaがリストされています)
Fabien Snauwaert

2
@FabienSnauwaert以下を比較することで重複の一部を取り除くことができます(より大きい)
Michael

@TechTravelThinkあなたの答えは非常に明確です、そのおかげですが、大きなテーブルでは時間がかかり(20'000エントリテーブルでは約2分)、25の最初の結果を表示した後、クリックして次の結果を表示すると、phpmyadmin show error "# 1052-order句の列 'id'があいまいです
bcag2

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

1
いいえ、これはおそらくロットの中で最も遅いためです。副選択は、返されるすべての行に対して実行されるため、非常に低速です。
Oddman '21

10

従業員の名前列で重複しているレコードの数を見つけるには、以下のクエリが役立ちます。

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

10

重複を含むすべてのデータを取得するには、これを使用しました:

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 =使用しているテーブル。

DupliactedData =探している重複データ。


これは、それ自身の行の各重複を示しています。それだけが必要。ありがとう。
ウォームウィスキー

8

私の最後のクエリには、ここで役立ついくつかの回答が組み込まれています-グループ化、カウント、GROUP_CONCATの組み合わせ

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

これにより、両方の例のID(カンマ区切り)、必要なバーコード、および重複の数が提供されます。

それに応じてテーブルと列を変更します。


8

重複という点で多くの用途があるJOINアプローチは見ていません。

このアプローチでは、実際に2倍の結果が得られます。

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
参考:複数の重複レコードが存在する可能性がある場合は、「個別の列を選択する」を選択します。それ以外の場合、結果には、見つかった重複行の重複が含まれます。
ドリュー

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

都市をテーブルに置き換えます。名前をフィールド名に置き換えます



6

上記の結果を確認したところ、重複している単一の列の値をチェックする必要がある場合、クエリは正常に機能します。たとえばメール。

しかし、より多くの列でチェックする必要があり、結果の組み合わせをチェックして、このクエリが正しく機能するようにしたい場合は、次のようにします。

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)

まさに必要なもの!ここに私のクエリは、重複の3つのフィールドをチェック:SELECT COUNT(CONCAT(userid,event,datetime)) AS total, userid, event, datetime FROM mytable GROUP BY CONCAT(userid, event, datetime ) HAVING total>1
甲斐ノアック

4

行全体を確認できるため、重複を見つけるためにウィンドウ関数(MySQL 8.0+)を使用することを好みます。

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デモ


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
同じサブクエリを2回実行するのは非効率的です。
NobleUplift 2014


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
クエリ対象の列にインデックスが作成されていない場合、これは耐えられないほど遅いか、または完了しない可能性があることに注意してください。それ以外の場合、重複した行のすべてのID に変更a.emaila.*て取得することができました。
NobleUplift 2014

@NobleUplift何のことをいっているのですか。
マイケル

@Michaelまあ、これは3歳なので、使用しているMySQLのどのバージョンでもテストすることはできませんが、選択した列にインデックスがないデータベースで同じクエリを試したので、かなり時間がかかりました。数秒で終了します。それをSELECT DISTINCT a.*ほぼ瞬時に解決するように変更します。
NobleUplift

@NobleUpliftああ、わかりました。遅いのは理解できますが…気になる部分は「終わらないかもしれません」。
マイケル

@Michaelこのクエリを実行する必要があったシステムのテーブルを覚えていませんが、数百万のレコードがあるテーブルでは、おそらく終了していましたが、時間がかかりすぎて、いつ表示するかをあきらめました。実際に終了します。
NobleUplift

1

複数のフィールドを持つ重複する行を削除するには、最初にそれらを異なる行のみに指定された新しい一意のキーに分類し、次に「group by」コマンドを使用して同じ新しい一意のキーを持つ重複する行を削除します。

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;

説明も追加できますか?
ロバート

なぜ使用しないのCREATE TEMPORARY TABLE ...ですか?あなたの解決策の少しの説明は素晴らしいでしょう。
maxhb 2016

1

1つの非常に遅い貢献...それが誰かを助けてくれる場合に備えて...銀行アプリで一致するトランザクションのペア(実際にはアカウント間の送金の両側)を見つけて、どのトランザクションを識別するかというタスクがありました各アカウント間転送トランザクションの「from」と「to」であったため、次のようになりました。

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;

その結果、DuplicateResultsTableは一致する(つまり重複する)トランザクションを含む行を提供しますが、同じペアが2回目に一致するときには同じトランザクションIDを逆に提供するためSELECT、最初のトランザクションIDでグループ化するために外部が存在します。LEASTおよびGREATESTを使用して、2つのトランザクションIDが結果で常に同じ順序になるようにします。これGROUPにより、最初のトランザクションIDが安全になり、重複するすべての一致が排除されます。100万近くのレコードを調べ、わずか2秒足らずで12,000以上の一致を特定しました。もちろん、transactionidはプライマリインデックスであり、これは本当に役立ちました。




1

重複使用を削除したい場合 DISTINCT

それ以外の場合は、次のクエリを使用します。

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


0

このクエリを使用してみてください:

SELECT name, COUNT(*) value_count FROM company_master GROUP BY name HAVING value_count > 1;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.