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

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

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

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

    サンプルデータ

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

    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
    

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

    主キーの列は、重複する行がないことを保証します。これは、主キーがデータの整合性を強化するのに役立つため、RDBMSでは適切な方法です。ただし、主キーは行の重複を防ぐため、重複を見つける機能を妨げる可能性があります。

    上記の表では、主キー列は増分番号であり、その値は意味を持たず、重要ではありません。したがって、他の列で重複を見つけたい場合は、その行を無視する必要があります。

    オプション1

    SQL GROUP BYを使用できます 句を使用して列を重要な列でグループ化し、COUNT()を使用します 同一の行数を返す関数:

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

    結果:

     firstname | lastname | count 
    -----------+----------+-------
     Ruff      | Robinson |     1
     Wag       | Johnson  |     3
     Woof      | Jones    |     1
     Bark      | Smith    |     2

    ここでは、クエリから主キー列を省略して除外しました。

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

    オプション2

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

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

    結果:

     firstname | lastname | count 
    -----------+----------+-------
     Wag       | Johnson  |     3
     Bark      | Smith    |     2

    オプション3

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

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

    結果:

        dogname    | count 
    ---------------+-------
     Wag Johnson   |     3
     Ruff Robinson |     1
     Woof Jones    |     1
     Bark Smith    |     2

    オプション4

    または、ROW_NUMBER()を使用することもできます ウィンドウ関数:

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

    結果:

     dogid | firstname | lastname | row_number 
    -------+-----------+----------+------------
         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

    PARTITIONの使用 句を指定すると、新しい列が追加され、重複するたびに行番号が増加しますが、一意の行があると再びリセットされます。

    この場合、結果はグループ化されません。つまり、一意の識別子列を含む、重複する各行を確認できます。

    オプション5

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

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

    結果:

     dogid | firstname | lastname | row_number 
    -------+-----------+----------+------------
         2 | Bark      | Smith    |          2
         6 | Wag       | Johnson  |          2
         7 | Wag       | Johnson  |          3

    これにより、非重複が出力から除外され、各重複の1行が出力から除外されます。つまり、重複からの余分な行のみが表示されます。これらの行は、重複排除操作で削除される主な候補です。

    オプション6

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

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

    結果:

     dogid | firstname | lastname 
    -------+-----------+----------
         6 | Wag       | Johnson
         2 | Bark      | Smith
         7 | Wag       | Johnson

    この例と前の例の違いの1つは、この例では独自の行番号を生成する必要がないことです。

    オプション7

    Postgresで重複行を返すためのさらに別のオプションは次のとおりです。

    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. MySQLで移動平均を計算する方法

    2. SQL * Plus/SQLcl出力グリッドに垂直方向の境界線を追加する方法

    3. GoogleBigQueryODBCドライバー

    4. エラー:ORA-65096:Oracleの共通ユーザーまたはロール名が無効です