重複するレコードを削除する

しゃみなー
質問: 重複を削除したい
テーブルに同じ内容のレコードが複数あるのです。重複レコードを削除して1レコードにしたいのです。どんなSQLで対応できますか?

重複するレコードを確認して削除するSQLを紹介します。

方針

重複を定義する

はじめに、どのカラムがすべて同じなら「重複」とみなすのかを明確にします。 (例:name、email、birthdateがすべて同じなら重複とみなす。など)

主キー(idなど)は通常重複していないので、重複チェックの対象から除きます。

残すレコードの基準を決める

重複レコードの中でどれを「残す」かを決めます。シナリオによっては、残さないという方針もあります。

よくある基準では以下があります。

  • idが最小のものを残す
  • created_atが最も古いものを残す

重複を検出して、削除する対象を特定する

重複レコードを検出して削除します。

以下のテーブルを作成します。

Products テーブル
idnamepricecategory
1商品A1000食品
2商品A1000食品
3商品A1000食品
4商品B2000家電
5商品B2000家電
6商品C1500衣料
7商品D3000食品
8商品E1000食品
9商品A1000飲料


挿入レコードのSQL
INSERT INTO [dbo].[ProductsH] ([name], [price], [category]) VALUES
(N'商品A', 1000, N'食品'),
(N'商品A', 1000, N'食品'),
(N'商品A', 1000, N'食品'),
(N'商品B', 2000, N'家電'),
(N'商品B', 2000, N'家電'),
(N'商品C', 1500, N'衣料'),
(N'商品D', 3000, N'食品'),
(N'商品E', 1000, N'食品'),
(N'商品A', 1000, N'飲料');

重複レコードの確認

以下のSQLを実行して、重複しているレコードを確認します。name, price, category の値が一致した場合に重複レコードとみなします。

SELECT name, price, category, COUNT(*) AS duplicate_count
FROM [dbo].[Products] GROUP BY [name], [price], [category] HAVING COUNT(*) > 1


結果は以下です。

#[pre class="brush:sql"]]

namepricecategoryduplicate_count
商品A1000食品3
商品B2000家電2

重複レコードの削除

以下のSQLを実行して、重複しているレコードを削除します。
name, price, category の値が一致した場合に重複レコードとみなします。

WITH Duplicates AS (
    SELECT 
        id,
        ROW_NUMBER() OVER (
            PARTITION BY [name], [price], [category]
            ORDER BY id
        ) AS rn
    FROM dbo.Products
)
DELETE FROM dbo.Products
WHERE id IN (
    SELECT id FROM Duplicates WHERE rn > 1
);

解説

以下では、PARTITION BY で重複するレコードをIDの小さい順にrn列に1から値を割り当てます。

    SELECT 
        id,
        ROW_NUMBER() OVER (
            PARTITION BY [name], [price], [category]
            ORDER BY id
        ) AS rn
    FROM dbo.Products


上記のSQLの実行結果は以下になります。

idrn
91
11
22
33
41
52
61
71
81


rnが2以上のレコードを削除すると重複を除去できます。

WITH Duplicatesは「共通テーブル式」(CTE: Common Table Expression)で、このSQL内で利用できる一時的な名前付きのクエリ結果です。 共通テーブル式についてはこちらの記事を参照してください。
削除するIDを先の結果のDuplicatesの共通テーブル式から参照して、レコードを削除します。

DELETE FROM dbo.Products
WHERE id IN (
    SELECT id FROM Duplicates WHERE rn > 1
);

実行結果

実行結果は以下となります。重複していたレコードを削除できました。

idnamepricecategory
1商品A1000食品
4商品B2000家電
6商品C1500衣料
7商品D3000食品
8商品E1000食品
9商品A1000飲料


AuthorPortraitAlt
著者
iPentecのプログラマー、最近はAIの積極的な活用にも取り組み中。
とっても恥ずかしがり。
作成日: 2025-06-21
Copyright © 1995–2025 iPentec all rights reserverd.