MEDIA

メディア

  1. TOP
  2. メディア
  3. プログラミング
  4. SQLで重複レコードを抽出する方法|GROUP BY・JOIN・削除まで完全解説

SQLで重複レコードを抽出する方法|GROUP BY・JOIN・削除まで完全解説

「SQLで重複データを見つけたい」
「ユニーク制約を付ける前に既存データを点検したい」
「JOIN後にレコードが想定以上に増えた原因を調べたい」

このような悩みは、データベースを扱う現場で非常によく発生します。

特に、

  • データ移行・CSV取り込み時の品質チェック
  • 顧客マスタ・会員情報のクレンジング
  • 分析用データの前処理
  • ユニークインデックス追加前の事前検証

といった場面では、「重複レコードの正確な抽出」は必須スキルです。

本記事では、以下を体系的に解説します。

  • 重複の正しい定義の決め方
  • GROUP BY + HAVINGによる重複キー抽出
  • 重複行を全件取得する方法(サブクエリ・自己結合)
  • 複数列(複合キー)の重複抽出
  • 大量データでのパフォーマンス最適化
  • 安全な削除・除外の考え方

基礎から実務レベルまで、網羅的に解説します。

重複レコードとは何か?まず定義を決める

重複抽出で最も重要なのは「定義」

SQLを書く前に、必ず明確にすべきことがあります。

何をもって「重複」とするのか?

例えば:

  • メールアドレスが同じなら重複?
  • 電話番号+都道府県の組み合わせが同じなら重複?
  • NULLは重複として扱う?

ここが曖昧なままクエリを書くと、正しいSQLでも「欲しい結果にならない」状態になります。

 

単一列の重複

例:

  • email が同じ
  • phone_number が同じ

この場合、GROUP BY email のように1列だけを基準にします。

複数列(複合キー)の重複

例:

  • email + service_type
  • product_id + shop_id
  • name + birthday

この場合は:

GROUP BY email, service_type

のように複数列を指定します。

業務上「一意であるべき単位」を明文化することが重要です。

キーだけ欲しいのか?行全体が必要か?

重複抽出には2種類あります。

目的 取得対象
重複値の確認 キーのみ
修正・削除対象の特定 行全体

用途によりSQLが変わります。

重複キーだけを抽出する(GROUP BY + HAVING)

基本構文

SELECT phone_number, COUNT(*) AS duplicate_count
FROM customer
GROUP BY phone_number
HAVING COUNT(*) > 1;

解説

  • GROUP BY でキーごとに集計
  • COUNT(*) で件数を算出
  • HAVING で2件以上を抽出

これが重複抽出の基本パターンです。

COUNT(*) と COUNT(列) の違い

書き方 NULLを数えるか
COUNT(*) 数える
COUNT(column) 数えない

NULLをどう扱うかは必ず要件で確認します。

重複件数順に並べる

ORDER BY duplicate_count DESC;

実務では「多い順」に見るのが効率的です。

重複している行を全件取得する方法

キーだけでは削除・修正はできません。
元の行をすべて取得する方法を解説します。

方法①:サブクエリ(IN)

SELECT *
FROM customer
WHERE phone_number IN (
SELECT phone_number
FROM customer
GROUP BY phone_number
HAVING COUNT(*) > 1
)
ORDER BY phone_number, id;

特徴

  • 分かりやすい
  • 調査用途に最適
  • 初心者にも扱いやすい

方法②:自己結合(JOIN)

SELECT c.*, d.duplicate_count
FROM customer c
JOIN (
SELECT phone_number, COUNT(*) AS duplicate_count
FROM customer
GROUP BY phone_number
HAVING COUNT(*) > 1
) d
ON c.phone_number = d.phone_number
ORDER BY c.phone_number, c.updated_at DESC;

特徴

  • 件数を持ち回れる
  • 実務向き
  • 分析用途に強い

複数列の重複抽出

SELECT email, service_type, COUNT(*) AS duplicate_count
FROM users
GROUP BY email, service_type
HAVING COUNT(*) > 1;

考え方は単一列と同じです。

列を増やすと重複は減り、減らすと重複は増えます。

入力ゆれ対策(実務で必須)

重複の原因の多くは入力ゆれです。

  • 大文字小文字
  • 前後の空白
  • 全角半角
  • ハイフン有無

例:

GROUP BY LOWER(TRIM(email))

ただし関数を使うとインデックスが効かなくなる可能性があります。

対策:

  • 取り込み時に正規化
  • 正規化済みカラムを持つ
  • アプリ側で統一

大量データでの注意点

重複抽出は高負荷になりやすい処理です。

インデックスの確認

キー列にインデックスがあるか確認。

  • 単一インデックス
  • 複合インデックス

実行計画の確認

  • MySQL: EXPLAIN
  • PostgreSQL: EXPLAIN ANALYZE
  • SQL Server: 実行プラン表示

公式ドキュメントも参考になります:

範囲を絞って検証

いきなり全期間で実行しない。

WHERE created_at >= '2026-01-01'

段階的に確認するのが安全です。

重複の除外・最大以外を除外する方法

最新だけ残す(ウィンドウ関数)

SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY phone_number
ORDER BY updated_at DESC
) AS rn
FROM customer
) t
WHERE rn = 1;

ウィンドウ関数は実務で非常に強力です。

削除の考え方(重要)

削除前に必ず:

  1. SELECTで対象確認

  2. 件数確認

  3. バックアップ取得

  4. トランザクション内で実行

重複原因が取り込みロジックなら、削除だけでは再発します。

よくある失敗パターン

① DISTINCTで重複抽出しようとする

DISTINCT はユニーク一覧を作るものであり、重複検知には不向き。

② 重複定義が曖昧

SQLの問題ではなく要件定義の問題。

③ インデックス無視

関数適用でインデックスが無効化される。

④ 本番データでいきなりDELETE

事故の典型パターン。

まとめ

SQLで重複レコードを抽出する流れは次の通りです。

  1. 重複の定義を明確にする

  2. GROUP BY + HAVING でキー抽出

  3. サブクエリ or JOINで行全件取得

  4. 複数列重複にも対応

  5. 実行計画とインデックス確認

  6. 安全な削除手順を踏む

この型を持っておけば、どのRDBMSでも応用できます。

次のステップへ

データ品質の担保やパフォーマンス改善に強いエンジニアは、どの企業でも重宝されます。

私たちは、

  • SQL最適化
  • データ設計
  • 大規模データ分析基盤構築
  • パフォーマンスチューニング

といった分野に強みを持つ技術チームです。

本記事の内容に強い関心を持った方、
「より高度なデータ設計・パフォーマンス最適化に挑戦したい」と感じた方へ。

現在、データベース・バックエンド領域を一緒に深めていく仲間を募集しています。

技術に真剣に向き合える環境で、
あなたのSQLスキルを次のレベルへ引き上げてみませんか。

学んだSQLを、実務で使えるスキルにしたい方へ

本記事ではSQLの基本的な考え方や使い方を解説しましたが、
「実務で使えるレベルまで身につけたい」と感じた方も多いのではないでしょうか。

SQLは、文法を理解するだけでなく、

  • どんなデータ構造で使われるのか
  • どんなクエリが現場で求められるのか

を意識して学ぶことで、実践力が大きく変わります。

そうした「実務を見据えたSQL学習」を進めたい方には、
完全無料で学べるプログラミングスクール ZeroCode という選択肢もあります。

  • SQLを含むWeb・データベース系スキルを体系的に学べる
  • 未経験者でも実務を意識したカリキュラム
  • 受講料・教材費がかからない完全無料の学習環境
  • 完全オンラインでスキマ学習


ZeroCodeについて詳しく見る

※学習内容や進め方を確認するだけでもOKです

Join us! 未経験からエンジニアに挑戦できる環境で自分の可能性を信じてみよう 採用ページを見る→

記事監修

ドライブライン編集部

[ この記事をシェアする ]

記事一覧へ戻る