Zde je sedm možností pro nalezení duplicitních řádků na serveru SQL Server, pokud tyto řádky mají primární klíč nebo jiný sloupec jedinečného identifikátoru.
Jinými slovy, tabulka obsahuje dva nebo více řádků, které sdílejí přesně stejné hodnoty ve všech sloupcích kromě sloupce s jedinečným identifikátorem.
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 duplikáty (kromě DogId
sloupec, který obsahuje jedinečnou hodnotu ve všech řádcích a lze jej použít jako sloupec primárního klíče tabulky). Můžeme také vidět, že poslední tři řádky jsou duplikáty (kromě DogId
sloupec).
Jedinečný sloupec ID zajišťuje, že neexistují žádné duplicitní řádky, což je obvykle vysoce žádoucí vlastnost v RDBMS. V tomto případě však může narušit naši schopnost najít duplikáty. Podle definice sloupec jedinečného ID zajišťuje, že neexistují žádné duplikáty. Naštěstí můžeme tento problém překonat poměrně snadno, jak ukazují následující příklady.
Možnost 1
Pravděpodobně nejjednodušší/nejjednodušší způsob, jak to udělat, je pomocí jednoduchého dotazu, který používá GROUP BY
klauzule:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Výsledek:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Woof | Jones | 1 | | Ruff | Robinson | 1 | | Bark | Smith | 2 | +-------------+------------+---------+
Podařilo se nám vyloučit sloupec primárního klíče/jedinečného ID tím, že jsme jej vynechali z našeho dotazu.
Výsledek nám říká, že existují tři řádky obsahující Wag Johnson a dva řádky obsahující Bark Smith. Toto jsou duplikáty (nebo triplikáty v případě Waga Johnsona).
Možnost 2
Neduplikáty můžeme z výsledku vyloučit zahrnutím HAVING
klauzule v našem dotazu:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Výsledek:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Bark | Smith | 2 | +-------------+------------+---------+
Možnost 3
Můžeme také zkontrolovat duplikáty na zřetězených sloupcích. Můžeme například použít CONCAT()
funkce pro spojení našich dvou sloupců:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Výsledek:
+---------------+---------+ | DogName | Count | |---------------+---------| | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+---------+
Možnost 4
Můžeme použít ROW_NUMBER()
pomocí funkce PARTITION BY
klauzule k vytvoření nového sloupce s číslem řádku, které se zvyšuje pokaždé, když je duplikát, ale znovu se resetuje, když existuje jedinečný řádek:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Výsledek:
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 1 | Bark | Smith | 1 | | 2 | Bark | Smith | 2 | | 4 | Ruff | Robinson | 1 | | 5 | Wag | Johnson | 1 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | | 3 | Woof | Jones | 1 | +---------+-------------+------------+--------------+
Jednou z výhod této metody je, že můžeme vidět každý duplicitní řádek spolu s jeho sloupcem s jedinečným identifikátorem, protože výsledky neseskupujeme.
Možnost 5
Předchozí příklad můžeme také použít jako běžný tabulkový výraz ve větším dotazu:
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 | +---------+-------------+------------+--------------+
Tato možnost vyloučí z výstupu neduplikáty.
Z výstupu také vyloučí přesně jeden řádek každého duplikátu. Tím se nám otevírají dveře k otočení posledního SELECT *
do DELETE
pro odstranění duplicit v tabulce při zachování jednoho z každého duplikátu.
Možnost 6
Zde je stručnější způsob, jak získat stejný výstup jako v předchozím příkladu:
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 | +-------+-----------+----------+
Tento příklad nevyžaduje generování vlastního samostatného čísla řádku.
Možnost 7
A nakonec je zde trochu komplikovanější technika vrácení duplicitních řádků:
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 | +---------+-------------+------------+---------+-------------+------------+
I výsledek vypadá spletitěji, ale stále nám ukazuje duplikáty!