sql >> Database teknologi >  >> RDS >> Oracle

SQL Find duplikat med flere felter (ingen unikke ID) BEMÆRK

Lad os få nogle interessante data med kædede dubletter på forskellige attributter:

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
 

Nu kan vi få nogle relationer ved hjælp af analytiske funktioner (uden nogen joinforbindelser):

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;
 

Hvilket giver:

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

Men det opfatter ikke, at #4 er relateret til #5, som er relateret til #2 og derefter til #1...

Dette kan findes med en hierarkisk forespørgsel:

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

Men det vil give mange, mange duplikerede rækker (da den ikke ved, hvor den skal starte hierarkiet fra, så vil hver række efter tur vælges som rod) - i stedet kan du bruge den første forespørgsel til at give den hierarkiske forespørgsel et udgangspunkt, når ID og DUPLICATE_OF værdierne er de samme:

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

Hvilket giver:

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

Der er stadig nogle rækker, der er duplikeret på grund af de lokale minima i søgningen, der opstår en #4 ... som kan fjernes med en simpel 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;
 

Hvilket giver output:

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. Håndtering af EXCEPTION og returner resultat fra funktion

  2. sql slette alle rækker ældre end 30 dage

  3. Hvordan vælger man den n'te række i en SQL-databasetabel?

  4. VB.NET MySQL-forbindelse