sql >> Databáze >  >> RDS >> Sqlserver

3 způsoby, jak odstranit duplicitní řádky na serveru SQL při ignorování primárního klíče

Následující příklady používají T-SQL k odstranění duplicitních řádků na serveru SQL Server a ignorují sloupec primárního klíče nebo jedinečného identifikátoru.

Přesněji řečeno, příklady odstraní duplicitní řádky, ale ponechají jeden. Takže po dvou stejných řádcích se jeden vymaže a druhý zůstane. To se často nazývá „deduplikace“ tabulky, „deduplikace“ tabulky atd.

Ukázková data

Předpokládejme, že máme tabulku s následujícími údaji:

SELECT * FROM Dogs;

Výsledek:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 2       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
| 6       | Wag         | Johnson    |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

Vidíme, že první dva řádky jsou duplicitní, stejně jako poslední tři řádky.

Možnost 1

Nejprve spusťte následující kód, abyste zkontrolovali, které řádky budou deduplikovány:

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

Výsledek:

+---------+-------------+------------+--------------+
| DogId   | FirstName   | LastName   | Row_Number   |
|---------+-------------+------------+--------------|
| 2       | Bark        | Smith      | 2            |
| 6       | Wag         | Johnson    | 2            |
| 7       | Wag         | Johnson    | 3            |
+---------+-------------+------------+--------------+

Použili jsme ROW_NUMBER() pomocí funkce PARTITION BY klauzule k vytvoření vlastního čísla řádku, které se zvýší, když jsou nalezeny jakékoli duplikáty, a resetuje se, když je nalezen neduplikát. Číslo větší než 1 znamená, že se jedná o duplikát, a proto vracíme pouze řádky, které mají číslo větší než 1.

Vidíme, že při odstranění duplicit v této tabulce budou odstraněny tři řádky.

Nyní deduplikujeme tabulku:

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

Výsledek:

(3 rows affected)

Podle očekávání byly smazány tři řádky.

Tento dotaz je téměř totožný s předchozím. Vše, co jsme udělali, byla změna SELECT * na posledním řádku DELETE .

Nyní vyberte všechny řádky z tabulky, abychom ověřili, že byly odstraněny správné řádky:

SELECT * FROM Dogs;

Výsledek:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
+---------+-------------+------------+

Vidíme, že každý pes se nyní v tabulce objeví pouze jednou.

Možnost 2

Za předpokladu, že tabulka byla obnovena po předchozím příkladu, zde je další způsob kontroly duplikátů:

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

Výsledek:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 2       | Bark        | Smith      |
| 6       | Wag         | Johnson    |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

V tomto případě jsme použili EXCEPT operátor spolu s MIN() funkce. Mohli bychom nahradit MIN() s MAX() podle toho, které řádky chceme smazat.

Chcete-li odstranit řádky, můžeme jednoduše nahradit SELECT * pomocí DELETE :

DELETE FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    EXCEPT SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Výsledek:

(3 rows affected)

A zkontrolujte, co zbývá:

SELECT * FROM Dogs;

Výsledek:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
+---------+-------------+------------+

Možnost 3

Dalším způsobem, jak to udělat, je připojit se k tabulce a zkontrolovat duplikáty tímto způsobem.

Za předpokladu, že tabulka byla obnovena po předchozím příkladu, zde je naše třetí možnost pro výběr duplikátů:

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

Výsledek:

+---------+-------------+------------+---------+-------------+------------+
| DogId   | FirstName   | LastName   | DogId   | FirstName   | LastName   |
|---------+-------------+------------+---------+-------------+------------|
| 2       | Bark        | Smith      | 1       | Bark        | Smith      |
| 7       | Wag         | Johnson    | 5       | Wag         | Johnson    |
| 7       | Wag         | Johnson    | 6       | Wag         | Johnson    |
+---------+-------------+------------+---------+-------------+------------+

Tento výsledek není tak jasný jako ten v předchozím příkladu, ale stále vidíme, které řádky jsou duplicitní.

Nyní můžeme tento dotaz upravit tak, že odstraníme duplicitní řádky:

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    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
    )
);

Výsledek:

(3 rows affected)

Opět byly smazány tři řádky.

Podívejme se znovu na tabulku:

SELECT * FROM Dogs;

Výsledek:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 2       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

Můžete si všimnout, že tentokrát byly ostatní řádky odstraněny. Jinými slovy, nyní máme DogId s 2, 3, 4 a 7, zatímco v předchozích příkladech nám zůstaly 1, 3, 4 a 5.

Tento příklad můžeme snadno změnit, abychom smazali stejné řádky jako předchozí příklady. K tomu můžeme použít MIN() místo funkce MAX() funkce:

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    FROM Dogs d1, Dogs d2 
    WHERE d1.FirstName = d2.FirstName 
    AND d1.LastName = d2.LastName 
    AND d1.DogId <> d2.DogId 
    AND d1.DogId=( 
        SELECT MIN(DogId) 
        FROM Dogs d3 
        WHERE d3.FirstName = d1.FirstName 
        AND d3.LastName = d1.LastName
    )
);

  1. Použití isql s připojovacím řetězcem

  2. Top 5 bezplatných nástrojů pro návrh databáze

  3. Jak omezit výsledky v MySQL, PostgreSQL a SQLite

  4. Existuje způsob, jak zakázat aktualizace/mazání, ale přesto umožnit spouštěčům je provádět?