Oracle
 sql >> Baza danych >  >> RDS >> Oracle

SQL Znajdź duplikat z kilkoma polami (bez unikalnego identyfikatora) OBEJŚCIE

Miejmy kilka interesujących danych z połączonymi duplikatami w różnych atrybutach:

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

Teraz możemy uzyskać kilka relacji za pomocą funkcji analitycznych (bez żadnych złączeń):

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;

Co daje:

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

Ale to nie oznacza, że ​​#4 jest powiązany z #5, który jest powiązany z #2, a następnie z #1...

Można to znaleźć za pomocą zapytania hierarchicznego:

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 );

Ale to da wiele, wiele zduplikowanych wierszy (ponieważ nie wie, od czego zacząć hierarchię, więc wybierze każdy wiersz po kolei jako główny) - zamiast tego możesz użyć pierwszego zapytania, aby nadać zapytaniu hierarchicznemu punkt wyjścia, gdy ID i DUPLICATE_OF wartości są takie same:

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 );

Co daje:

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

Wciąż niektóre wiersze są zduplikowane z powodu lokalnych minimów w wyszukiwaniu, które występują jako #4 ..., które można usunąć za pomocą prostego 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;

Co daje wynik:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nadmiarowość Oracle RAC N+1

  2. Proste przypisanie SQL zmiennej Oracle

  3. Zapytanie o aktualizację Oracle za pomocą Join

  4. Oracle Invoke REST Service z pl/sql

  5. Używanie NVL dla wielu kolumn — Oracle SQL