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

SQL複数のフィールド(一意のIDなし)で重複を検索

    さまざまな属性で重複が連鎖している興味深いデータをいくつか見てみましょう:

    CREATE TABLE data ( ID, A, B, C ) AS
      SELECT 1, 1, 1, 1 FROM DUAL UNION ALL -- Related to #2 on column A
      SELECT 2, 1, 2, 2 FROM DUAL UNION ALL -- Related to #1 on column A, #3 on B & C, #5 on C
      SELECT 3, 2, 2, 2 FROM DUAL UNION ALL -- Related to #2 on columns B & C, #5 on C
      SELECT 4, 3, 3, 3 FROM DUAL UNION ALL -- Related to #5 on column A
      SELECT 5, 3, 4, 2 FROM DUAL UNION ALL -- Related to #2 and #3 on column C, #4 on A
      SELECT 6, 5, 5, 5 FROM DUAL;          -- Unrelated
    

    これで、分析関数を使用して(結合なしで)いくつかの関係を取得できます:

    SELECT d.*,
           LEAST(
             FIRST_VALUE( id ) OVER ( PARTITION BY a ORDER BY id ),
             FIRST_VALUE( id ) OVER ( PARTITION BY b ORDER BY id ),
             FIRST_VALUE( id ) OVER ( PARTITION BY c ORDER BY id )
           ) AS duplicate_of
    FROM   data d;
    

    ID A B C DUPLICATE_OF
    -- - - - ------------
     1 1 1 1            1
     2 1 2 2            1
     3 2 2 2            2
     4 3 3 3            4
     5 3 4 2            2
     6 5 5 5            6
    

    しかし、それは、#4が#2に関連し、次に#1に関連する#5に関連していることを理解していません...

    これは、階層クエリで見つけることができます:

    SELECT id, a, b, c,
           CONNECT_BY_ROOT( id ) AS duplicate_of
    FROM   data
    CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c );
    

    しかし、それは多くの重複した行を与えます(階層をどこから開始するかわからないため、各行をルートとして順番に選択します)-代わりに、最初のクエリを使用して、階層クエリに開始点を与えることができますID およびDUPLICATE_OF 値は同じです:

    SELECT id, a, b, c,
           CONNECT_BY_ROOT( id ) AS duplicate_of
    FROM   (
      SELECT d.*,
             LEAST(
               FIRST_VALUE( id ) OVER ( PARTITION BY a ORDER BY id ),
               FIRST_VALUE( id ) OVER ( PARTITION BY b ORDER BY id ),
               FIRST_VALUE( id ) OVER ( PARTITION BY c ORDER BY id )
             ) AS duplicate_of
      FROM   data d
    )
    START WITH id = duplicate_of
    CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c );
    

    ID A B C DUPLICATE_OF
    -- - - - ------------
     1 1 1 1            1
     2 1 2 2            1
     3 2 2 2            1
     4 3 3 3            1
     5 3 4 2            1
     1 1 1 1            4
     2 1 2 2            4
     3 2 2 2            4
     4 3 3 3            4
     5 3 4 2            4
     6 5 5 5            6
    

    #4 ...が発生する検索の極小値のために、まだいくつかの行が重複しています。これは、単純なGROUP BYで削除できます。 :

    SELECT id, a, b, c,
           MIN( duplicate_of ) AS duplicate_of
    FROM   (
      SELECT id, a, b, c,
             CONNECT_BY_ROOT( id ) AS duplicate_of
      FROM   (
        SELECT d.*,
               LEAST(
                 FIRST_VALUE( id ) OVER ( PARTITION BY a ORDER BY id ),
                 FIRST_VALUE( id ) OVER ( PARTITION BY b ORDER BY id ),
                 FIRST_VALUE( id ) OVER ( PARTITION BY c ORDER BY id )
               ) AS duplicate_of
        FROM   data d
      )
      START WITH id = duplicate_of
      CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c )
    )
    GROUP BY id, a, b, c;
    

    これにより、出力が得られます:

    ID A B C DUPLICATE_OF
    -- - - - ------------
     1 1 1 1            1
     2 1 2 2            1
     3 2 2 2            1
     4 3 3 3            1
     5 3 4 2            1
     6 5 5 5            6
    


    1. PostgreSQLで変数名のテーブルを作成することは可能ですか?

    2. mysqli拡張機能にdebianがありません

    3. PL / SQL内にOracleDatabaseオブジェクト・タイプを作成することは可能ですか?

    4. 複数の結合の最適化