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