Zde jsou čtyři metody, které můžete použít k nalezení duplicitních řádků na serveru SQL Server.
„Duplicitními řádky“ mám na mysli dva nebo více řádků, které sdílejí přesně stejné hodnoty ve všech sloupcích.
Ukázková data
Předpokládejme, že máme tabulku s následujícími údaji:
SELECT * FROM Pets;
Výsledek:
+---------+-----------+-----------+ | PetId | PetName | PetType | |---------+-----------+-----------| | 1 | Wag | Dog | | 1 | Wag | Dog | | 2 | Scratch | Cat | | 3 | Tweet | Bird | | 4 | Bark | Dog | | 4 | Bark | Dog | | 4 | Bark | Dog | +---------+-----------+-----------+
Vidíme, že první dva řádky jsou duplikáty, stejně jako poslední tři řádky.
Možnost 1
K vrácení informací o duplicitních řádcích můžeme použít následující dotaz:
SELECT
DISTINCT PetId,
COUNT(*) AS "Count"
FROM Pets
GROUP BY PetId
ORDER BY PetId;
Výsledek:
+---------+---------+ | PetId | Count | |---------+---------| | 1 | 2 | | 2 | 1 | | 3 | 1 | | 4 | 3 | +---------+---------+
Můžeme rozšířit SELECT
seznam, který v případě potřeby obsahuje další sloupce:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY PetId;
Výsledek:
+---------+-----------+-----------+---------+ | PetId | PetName | PetType | Count | |---------+-----------+-----------+---------| | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+---------+
Pokud má tabulka jedinečný identifikátor, můžeme tento sloupec z dotazu jednoduše odstranit. Pokud například předpokládáme, že PetId
je ve skutečnosti sloupec primárního klíče, který obsahuje jedinečné ID, mohli bychom spustit následující dotaz, abychom vrátili všechny řádky, které jsou duplicitní, nepočítaje sloupec primárního klíče:
SELECT
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetName,
PetType
ORDER BY PetName;
Výsledek:
+-----------+-----------+---------+ | PetName | PetType | Count | |-----------+-----------+---------| | Bark | Dog | 3 | | Scratch | Cat | 1 | | Tweet | Bird | 1 | | Wag | Dog | 2 | +-----------+-----------+---------+
Možnost 2
Pokud chceme vrátit pouze skutečné duplicitní řádky, můžeme přidat HAVING
klauzule:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
HAVING COUNT(*) > 1
ORDER BY PetId;
Výsledek:
+---------+-----------+-----------+---------+ | PetId | PetName | PetType | Count | |---------+-----------+-----------+---------| | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+---------+
Možnost 3
Dalším způsobem, jak to udělat, je použít ROW_NUMBER()
pomocí funkce PARTITION BY
klauzule k očíslování výstupu sady výsledků.
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets;
Výsledek:
+---------+-----------+-----------+--------------+ | PetId | PetName | PetType | Row_Number | |---------+-----------+-----------+--------------| | 1 | Wag | Dog | 1 | | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 1 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+--------------+
PARTITION BY
klauzule rozděluje sadu výsledků vytvořenou FROM
klauzule do oddílů, na které je funkce aplikována. Když určíme oddíly pro sadu výsledků, každý oddíl způsobí, že číslování začne znovu (tj. číslování začne na 1 pro první řádek v každém oddílu).
Možnost 4
Pokud chceme, aby byly vráceny pouze přebytečné řádky z odpovídajících duplikátů, můžeme použít výše uvedený dotaz jako společný tabulkový výraz, například takto:
WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets
)
SELECT * FROM CTE WHERE Row_Number <> 1;
Výsledek:
+---------+-----------+-----------+--------------+ | PetId | PetName | PetType | Row_Number | |---------+-----------+-----------+--------------| | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+--------------+
Jednou z výhod toho je, že můžeme odstranit duplicitní řádky jednoduše přepnutím SELECT *
na DELETE
(na posledním řádku).
Můžeme tedy použít výše uvedený kód, abychom viděli, které řádky budou smazány, a když jsme spokojeni s tím, že smažeme správné řádky, můžeme jej přepnout na DELETE
příkaz k jejich skutečnému smazání.
Takhle:
WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets
)
DELETE FROM CTE WHERE Row_Number <> 1;