Proste usunięcie duplikatów

Dzisiaj prezentacja prostego sposobu na pozbycie się wszystkich rekordów, które nie są takie same ale niestety mają ten sam klucz.

Do wykonania takiej operacji posłużymy się oczywiście grupowaniem, ale nie tym klasycznym które wszyscy znamy (GROUP BY), a partycjonowaniem danych przy użyciu funkcji okienkowych (PARTITION BY)
Wystarczy ponumerowac rekordy (ROW_NUMBER()) względem zadanej partycji sortując tak by zostały tylko te rekordy, które są dla nas ważne.
Warto również zapamiętac, że tabela użyta w CTE (common table expression, to cos zaczynające się od WITH) może byc przez to CTE modyfikowana! Łącznie z usunięciem 🙂

Do roboty.

Naszym zadaniem jest usunąc wszystkie NAJSTARSZE duplikaty klucza (pole Nazwa)  zostawiając jedynie najświeższy rekord (decyduje o tym pole DataDodania)
Tworzymy tabelkę i dodajemy dane.

SET NOCOUNT ON
DECLARE @T TABLE
    (
      Nazwa VARCHAR(30) ,
      DataDodania DATETIME
    )


INSERT  INTO @t
VALUES  ( 'MIPA', '2000-01-01' ),
        ( 'MIPA', '2002-01-01' ),
        ( 'MIPA', '2004-01-01' ),
        ( 'MIPA', '2015-01-01' ),
        ( 'KUPA', '2002-01-01' ),
        ( 'KUPA', '2007-01-01' ),
        ( 'TOMI', '2000-01-01' ),
        ( 'PIPO', '2010-01-01' ),
        ( 'PIPO', '2039-01-01' )
        
SELECT  *
FROM    @t

 

Zaczynamy numerować wiersze. Zobaczcie jak wygląda numerowanie z użyciem partycji i sortowaniem malejącym:

WITH    CTE
          AS ( SELECT   NumerWiersza = ROW_NUMBER() OVER ( PARTITION BY Nazwa ORDER BY DataDodania DESC ) ,
                        *
               FROM     @t
             )
    SELECT  *
    FROM    cte

 

SQL ponumerował nam każdy wiersz nadając jedynkę każdej partycji (grupie wierszy po kolumnie Nazwa). Pozostałe rekordy będą oczywiście numerowane 1+n aż do wystąpienia nowej wartości partycjonowanej.
Dlatego możemy wykonać na powyższym CTE operację usunięcia rekordów, których NumerWiersza będzie większy od jedynki!

WITH    CTE
          AS ( SELECT   NumerWiersza = ROW_NUMBER() OVER ( PARTITION BY NAzwa ORDER BY DataDodania DESC ) ,
                        *
               FROM     @t
             )
    DELETE  FROM cte
    WHERE   NumerWiersza > 1
    
SELECT  *
FROM    @t

 

Voilà!

Cały skrypt poniżej:

SET NOCOUNT ON
DECLARE @T TABLE
    (
      Nazwa VARCHAR(30) ,
      DataDodania DATETIME
    )


INSERT  INTO @t
VALUES  ( 'MIPA', '2000-01-01' ),
        ( 'MIPA', '2002-01-01' ),
        ( 'MIPA', '2004-01-01' ),
        ( 'MIPA', '2015-01-01' ),
        ( 'KUPA', '2002-01-01' ),
        ( 'KUPA', '2007-01-01' ),
        ( 'TOMI', '2000-01-01' ),
        ( 'PIPO', '2010-01-01' ),
        ( 'PIPO', '2039-01-01' )
        
SELECT  *
FROM    @t;
WITH    CTE
          AS ( SELECT   NumerWiersza = ROW_NUMBER() OVER ( PARTITION BY NAzwa ORDER BY DataDodania DESC ) ,
                        *
               FROM     @t
             )
    SELECT  *
    FROM    cte;
    
WITH    CTE
          AS ( SELECT   NumerWiersza = ROW_NUMBER() OVER ( PARTITION BY NAzwa ORDER BY DataDodania DESC ) ,
                        *
               FROM     @t
             )
    DELETE  FROM cte
    WHERE   NumerWiersza > 1
    
SELECT  *
FROM    @t

 

POST PIERWOTNIE OPUBLIKOWANY JAKO TSQL NA DZIŚ #30

Dodaj komentarz