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

主キーを無視してSQLServerの重複行を削除する3つの方法

    次の例では、T-SQLを使用して、主キーまたは一意の識別子の列を無視しながら、SQLServerの重複する行を削除します。

    より具体的には、例では重複する行を削除しますが、1つは保持します。したがって、2つの同一の行が与えられると、1つは削除され、もう1つは残ります。これは、テーブルの「重複排除」、テーブルの「重複排除」などと呼ばれることがよくあります。

    サンプルデータ

    次のデータを含むテーブルがあるとします。

    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行が重複しており、最後の3行も重複していることがわかります。

    オプション1

    まず、次のコードを実行して、重複排除される行を確認しましょう。

    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            |
    +---------+-------------+------------+--------------+

    ROW_NUMBER()を使用しました PARTITION BYで機能する 重複が見つかった場合は増分し、重複していないものが見つかった場合はリセットする独自の行番号を作成する句。 1より大きい数値は重複していることを示しているため、1より大きい数値のみを返します。

    このテーブルの重複排除を行うと、3つの行が削除されることがわかります。

    それでは、テーブルの複製を解除しましょう:

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

    結果:

    (3 rows affected)

    予想どおり、3行が削除されました。

    このクエリは前のクエリとほとんど同じです。 SELECT *を変更するだけでした DELETEの最後の行 。

    次に、正しい行が削除されたことを確認するために、テーブルからすべての行を選択しましょう。

    SELECT * FROM Dogs;

    結果:

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

    各犬がテーブルに1回だけ表示されるようになっていることがわかります。

    オプション2

    前の例の後にテーブルが復元されたと仮定して、重複をチェックする別の方法を次に示します。

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

    結果:

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

    この場合、EXCEPTを使用しました 演算子とMIN() 働き。 MIN()を置き換えることができます MAX()を使用 削除する行によって異なります。

    行を削除するには、SELECT *を置き換えるだけです。 DELETEを使用 :

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

    結果:

    (3 rows affected)

    そして、残っているものを確認してください:

    SELECT * FROM Dogs;

    結果:

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

    オプション3

    それを行う別の方法は、テーブル自体を結合し、その方法で重複をチェックすることです。

    前の例の後にテーブルが復元されたと仮定すると、重複を選択するための3番目のオプションは次のとおりです。

    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    |
    +---------+-------------+------------+---------+-------------+------------+

    この結果は前の例の結果ほど明確ではありませんが、どの行が重複しているかはわかります。

    これで、重複する行を削除するようにそのクエリを変更できます。

    DELETE FROM Dogs WHERE DogId IN (
        SELECT d2.DogId 
        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
        )
    );

    結果:

    (3 rows affected)

    もう一度、3つの行が削除されました。

    表をもう一度確認しましょう:

    SELECT * FROM Dogs;

    結果:

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

    今回は他の行が削除されていることに気付くかもしれません。つまり、DogIdができました。 ■2、3、4、および7ですが、前の例では1、3、4、および5が残っています。

    この例を簡単に変更して、前の例と同じ行を削除できます。これを行うには、MIN()を使用できます MAX()の代わりに関数 機能:

    DELETE FROM Dogs WHERE DogId IN (
        SELECT d2.DogId 
        FROM Dogs d1, Dogs d2 
        WHERE d1.FirstName = d2.FirstName 
        AND d1.LastName = d2.LastName 
        AND d1.DogId <> d2.DogId 
        AND d1.DogId=( 
            SELECT MIN(DogId) 
            FROM Dogs d3 
            WHERE d3.FirstName = d1.FirstName 
            AND d3.LastName = d1.LastName
        )
    );

    1. 各IDの最大値を取得するための単純なクエリ

    2. SQLiteでUnixタイムスタンプを返す2つの方法

    3. SQLite-テーブルを作成する

    4. psycopg2でバイナリCOPYテーブルFROMを使用します