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

Oracleで主キーを持つ重複行を見つける11の方法

    これらの行に主キーまたはその他の一意の識別子列があり、それを無視したい場合に、OracleDatabaseで重複行を返すための11のオプションを次に示します。

    サンプルデータ

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

    SELECT * FROM Dogs;

    結果:

    DOGID FIRSTNAME
    1 バーク スミス
    2 バーク スミス
    3 Woof ジョーンズ
    4 ラフ ロビンソン
    5 ワグ ジョンソン
    6 ワグ ジョンソン
    7 ワグ ジョンソン

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

    主キーの列は、重複する行がないことを保証します。これは、主キーがデータの整合性を強化するのに役立つため、RDBMSでは適切な方法です。ただし、主キーに一意の値が含まれているという事実は、重複を検索するときにその列を無視する必要があることを意味します。

    上記の表では、主キー列は増分番号であり、その値は意味を持たず、重要ではありません。したがって、重複を検索するときは、その列のデータを無視できます。

    オプション1

    重複を返すための最初のオプションは次のとおりです。

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

    結果:

    FIRSTNAME COUNT
    ワグ ジョンソン 3
    バーク スミス 2
    ラフ ロビンソン 1
    Woof ジョーンズ 1

    ここでは、 GROUP BYを使用してクエリを作成しました 出力が関連する列によってグループ化されるように句。 COUNT()も使用しました 同一の行の数を返す関数。そして、重複が最初に表示されるように、カウントの降順で並べ替えました。

    結果は、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
    ORDER BY Count DESC;

    結果:

    FIRSTNAME COUNT
    ワグ ジョンソン 3
    バーク スミス 2
    オプション3

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

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

    結果:

    DOGNAME COUNT
    ワグジョンソン 3
    バークスミス 2
    ラフロビンソン 1
    Woof Jones 1
    オプション4

    Oracleの各行にはrowidがあります 行のアドレスを返す疑似列。 rowid はテーブル内の行の一意の識別子であり、通常、その値はデータベース内の行を一意に識別します(ただし、同じクラスターに一緒に格納されている異なるテーブル内の行は同じ rowid

    とにかく、 rowidを使用するクエリを作成できます 必要に応じて:

    SELECT * FROM Dogs
    WHERE EXISTS (
      SELECT 1 FROM Dogs d2 
      WHERE Dogs.FirstName = d2.FirstName
      AND Dogs.LastName = d2.LastName
      AND Dogs.rowid > d2.rowid
    );

    結果:

    DOGID FIRSTNAME
    2 バーク スミス
    6 ワグ ジョンソン
    7 ワグ ジョンソン

    SELECT *を置き換えることができます DELETEを使用 テーブルに対して重複排除操作を実行します。

    DogIdを使用できた可能性があることに注意してください rowid の代わりにcolumn(主キー) 必要に応じて。そうは言っても、 rowid 何らかの理由で主キー列を使用できない場合、またはテーブルに主キーがない場合に役立ちます。

    オプション5

    rowidを使用する別のクエリを次に示します。 :

    SELECT * FROM Dogs
    WHERE rowid > (
      SELECT MIN(rowid) FROM Dogs d2  
      WHERE Dogs.FirstName = d2.FirstName
      AND Dogs.LastName = d2.LastName
    );

    結果:

    DOGID FIRSTNAME
    2 バーク スミス
    6 ワグ ジョンソン
    7 ワグ ジョンソン

    前の例と同様に、 SELECT *を置き換えることができます DELETEを使用 重複する行を削除します。

    オプション6

    2つのrowid 上記のオプションは、クエリで主キーを完全に無視する必要がある場合(または、主キー列がまったくない場合)に最適です。ただし、前述のように、 rowidを置き換えるオプションはまだあります。 主キー列を使用–この場合は DogId 列:

    SELECT * FROM Dogs
    WHERE EXISTS (
      SELECT 1 FROM Dogs d2 
      WHERE Dogs.FirstName = d2.FirstName
      AND Dogs.LastName = d2.LastName
      AND Dogs.DogId > d2.DogId
    );

    結果:

    DOGID FIRSTNAME
    2 バーク スミス
    6 ワグ ジョンソン
    7 ワグ ジョンソン
    オプション7

    そして、これが rowidを使用したもう1つのクエリです。 DogIdに置き換えられました 列:

    SELECT * FROM Dogs
    WHERE DogId > (
      SELECT MIN(DogId) FROM Dogs d2  
      WHERE Dogs.FirstName = d2.FirstName
      AND Dogs.LastName = d2.LastName
    );

    結果:

    DOGID FIRSTNAME
    2 バーク スミス
    6 ワグ ジョンソン
    7 ワグ ジョンソン
    オプション8

    重複を見つける別の方法は、 ROW_NUMBER()を使用することです。 ウィンドウ関数:

    SELECT 
        DogId,
        FirstName,
        LastName,
        ROW_NUMBER() OVER ( 
            PARTITION BY FirstName, LastName 
            ORDER BY FirstName, LastName
            ) AS row_num
    FROM Dogs;

    結果:

    DOGID FIRSTNAME ROW_NUM
    1 バーク スミス 1
    2 バーク スミス 2
    4 ラフ ロビンソン 1
    7 ワグ ジョンソン 1
    5 ワグ ジョンソン 2
    6 ワグ ジョンソン 3
    3 Woof ジョーンズ 1

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

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

    オプション9

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

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

    結果:

    DOGID FIRSTNAME ROW_NUM
    2 バーク スミス 2
    5 ワグ ジョンソン 2
    6 ワグ ジョンソン 3

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

    オプション10

    前の例と同じ出力を取得する別の方法は次のとおりです。

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

    結果:

    DOGID FIRSTNAME
    2 バーク スミス
    6 ワグ ジョンソン
    7 ワグ ジョンソン

    この例では、Oracleの MINUSを使用しています 演算子。最初のクエリで返された一意の行のみを返し、2番目のクエリでは返しません。

    MINUS 演算子はEXCEPTに似ています SQL Server、MariaDB、PostgreSQL、SQLiteなどの他のDBMSの演算子。

    オプション11

    テーブルから重複を選択するためのさらに別のオプションは次のとおりです。

    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 DOGID FIRSTNAME
    2 バーク スミス 1 バーク スミス
    7 ワグ ジョンソン 5 ワグ ジョンソン
    7 ワグ ジョンソン 6 ワグ ジョンソン

    1. PHPでwhileループと同じIDデータをリストするにはどうすればよいですか?

    2. RMANバックアップコマンド

    3. OracleSQLのカスタムオーダー

    4. 添付ファイルフィールドを持つテーブルの一括挿入または更新