sql >> データベース >  >> RDS >> Mysql

MySQLで主キーを無視して重複行を見つける7つの方法

    これらの行に主キーまたは他の一意の識別子列がある場合に、MySQLで重複行を返す7つの方法を次に示します。

    サンプルデータ

    例では、次のデータを使用します。

    DROP TABLE IF EXISTS Dogs;
    CREATE TABLE Dogs (
        DogId int PRIMARY KEY NOT NULL,
        FirstName varchar(50),
        LastName varchar(50)
        );
    
    INSERT INTO Dogs VALUES
        (1, 'Bark', 'Smith'),
        (2, 'Bark', 'Smith'),
        (3, 'Woof', 'Jones'),
        (4, 'Ruff', 'Robinson'),
        (5, 'Wag', 'Johnson'),
        (6, 'Wag', 'Johnson'),
        (7, 'Wag', 'Johnson');
    SELECT * FROM Dogs;

    結果:

    +-------+-----------+----------+
    | DogId | FirstName | LastName |
    +-------+-----------+----------+
    |     1 | Bark      | Smith    |
    |     2 | Bark      | Smith    |
    |     3 | Woof      | Jones    |
    |     4 | Ruff      | Robinson |
    |     5 | Wag       | Johnson  |
    |     6 | Wag       | Johnson  |
    |     7 | Wag       | Johnson  |
    +-------+-----------+----------+

    重複する行は、主キー/一意のID列を除いて、すべての列でまったく同じ値を共有します。

    最初の2行は重複しています(DogIdを除く) 列。これはテーブルの主キーであり、すべての行にわたって一意の値が含まれています)。最後の3行も重複しています(DogIdを除く) 列)。

    主キー列は、重複する行がないことを保証します。これは通常、RDBMSでは良いことです。ただし、定義上、これは重複がないことを意味します。この場合、主キー列は増分番号であり、その値は意味を持たず、重要ではありません。したがって、 である列で重複を見つけたい場合は、その行を無視する必要があります。 重要。

    オプション1

    最初のオプションは、GROUP BYを使用することです 句を使用して列を重要な列でグループ化し、COUNT()を使用します 同一の行数を返す関数:

    SELECT 
        FirstName, 
        LastName, 
        COUNT(*) AS Count
    FROM Dogs
    GROUP BY FirstName, LastName;

    結果:

    +-----------+----------+-------+
    | FirstName | LastName | Count |
    +-----------+----------+-------+
    | Bark      | Smith    |     2 |
    | Woof      | Jones    |     1 |
    | Ruff      | Robinson |     1 |
    | Wag       | Johnson  |     3 |
    +-----------+----------+-------+

    クエリから主キー列を省略することで、主キー列を無視することができました。

    結果は、Bark Smithを含む2つの行と、WagJohnsonを含む3つの行があることを示しています。これらは重複しています(またはWag Johnsonの場合は3回)。他の2つの行には重複がありません。

    オプション2

    HAVINGを使用すると、重複していないものを出力から除外できます。 条項:

    SELECT 
        FirstName, 
        LastName, 
        COUNT(*) AS Count
    FROM Dogs
    GROUP BY FirstName, LastName
    HAVING COUNT(*) > 1;

    結果:

    +-----------+----------+-------+
    | FirstName | LastName | Count |
    +-----------+----------+-------+
    | Bark      | Smith    |     2 |
    | Wag       | Johnson  |     3 |
    +-----------+----------+-------+
    オプション3

    連結された列の重複をチェックすることもできます。たとえば、CONCAT()を使用できます 2つの列を連結する関数は、DISTINCTを使用します キーワードを使用して個別の値を取得し、COUNT()を使用します カウントを返す関数:

    SELECT
        DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
        COUNT(*) AS Count
    FROM Dogs
    GROUP BY CONCAT(FirstName, ' ', LastName);

    結果:

    +---------------+-------+
    | DogName       | Count |
    +---------------+-------+
    | Bark Smith    |     2 |
    | Woof Jones    |     1 |
    | Ruff Robinson |     1 |
    | Wag Johnson   |     3 |
    +---------------+-------+
    オプション4

    または、ROW_NUMBER()を使用することもできます PARTITION BYで機能する 条項:

    SELECT 
        *,
        ROW_NUMBER() OVER ( 
            PARTITION BY FirstName, LastName 
            ORDER BY FirstName, LastName
            ) AS rn
    FROM Dogs;

    結果:

    +-------+-----------+----------+----+
    | DogId | FirstName | LastName | rn |
    +-------+-----------+----------+----+
    |     1 | Bark      | Smith    |  1 |
    |     2 | Bark      | Smith    |  2 |
    |     4 | Ruff      | Robinson |  1 |
    |     5 | Wag       | Johnson  |  1 |
    |     6 | Wag       | Johnson  |  2 |
    |     7 | Wag       | Johnson  |  3 |
    |     3 | Woof      | Jones    |  1 |
    +-------+-----------+----------+----+

    これにより、重複するたびに増加する行番号を持つ新しい列が作成されますが、一意の行があると再びリセットされます

    この手法は、結果をグループ化する必要がないという点で、考えられる利点を提供します。これは、一意の識別子列を含む、重複する各行を表示できることを意味します。

    オプション5

    前の例を、より大きなクエリの一般的なテーブル式として使用できます。

    WITH cte AS 
        (
            SELECT 
                *,
                ROW_NUMBER() OVER ( 
                    PARTITION BY FirstName, LastName 
                    ORDER BY FirstName, LastName
                    ) AS rn
            FROM Dogs
        )
    SELECT * FROM cte WHERE rn <> 1;

    結果:

    +-------+-----------+----------+----+
    | DogId | FirstName | LastName | rn |
    +-------+-----------+----------+----+
    |     2 | Bark      | Smith    |  2 |
    |     6 | Wag       | Johnson  |  2 |
    |     7 | Wag       | Johnson  |  3 |
    +-------+-----------+----------+----+

    この手法は、非重複を出力から除外し、各重複の1行を出力から除外します。

    このクエリは、重複排除操作の前兆として使用できます。重複を削除することにした場合、何が削除されるかを示すことができます。テーブルの重複排除を行うには、最後のSELECT *を置き換えるだけです。 DELETEを使用 。

    オプション6

    前の例と同じ出力を取得するためのより簡潔な方法は次のとおりです。

    SELECT * FROM Dogs 
    WHERE DogId IN (
        SELECT DogId FROM Dogs 
        WHERE DogId NOT IN (SELECT MIN(DogId) FROM Dogs
        GROUP BY FirstName, LastName)
        );

    結果:

    +-------+-----------+----------+
    | DogId | FirstName | LastName |
    +-------+-----------+----------+
    |     2 | Bark      | Smith    |
    |     6 | Wag       | Johnson  |
    |     7 | Wag       | Johnson  |
    +-------+-----------+----------+

    この手法では、ROW_NUMBER()を使用して個別の行番号を生成する必要はありません。 前の例のように。

    SELECT *を置き換えることもできます DELETEを使用 重複を削除します。

    オプション7

    そして最後に、重複を返すためのもう1つのオプションがあります:

    SELECT * 
    FROM Dogs d1, Dogs d2 
    WHERE d1.FirstName = d2.FirstName 
    AND d1.LastName = d2.LastName
    AND d1.DogId <> d2.DogId 
    AND d1.DogId = (
        SELECT MAX(DogId) 
        FROM Dogs d3 
        WHERE d3.FirstName = d1.FirstName 
        AND d3.LastName = d1.LastName
    );

    結果:

    +-------+-----------+----------+-------+-----------+----------+
    | DogId | FirstName | LastName | DogId | FirstName | LastName |
    +-------+-----------+----------+-------+-----------+----------+
    |     2 | Bark      | Smith    |     1 | Bark      | Smith    |
    |     7 | Wag       | Johnson  |     5 | Wag       | Johnson  |
    |     7 | Wag       | Johnson  |     6 | Wag       | Johnson  |
    +-------+-----------+----------+-------+-----------+----------+

    1. SQL Server:like?で使用されるインデックス列

    2. データベースに直接アクセスするための開発者ツール

    3. 実行プランでのインデックス付きビューのメンテナンス

    4. MySQLで1か月の日数を取得する方法