Ето четири метода, които можете да използвате, за да намерите дублиращи се редове в SQL Server.
Под „дублирани редове“ имам предвид два или повече реда, които споделят абсолютно еднакви стойности във всички колони.
Примерни данни
Да предположим, че имаме таблица със следните данни:
SELECT * FROM Pets;
Резултат:
+---------+-----------+-----------+ | PetId | PetName | PetType | |---------+-----------+-----------| | 1 | Wag | Dog | | 1 | Wag | Dog | | 2 | Scratch | Cat | | 3 | Tweet | Bird | | 4 | Bark | Dog | | 4 | Bark | Dog | | 4 | Bark | Dog | +---------+-----------+-----------+
Можем да видим, че първите два реда са дублирани, както и последните три реда.
Опция 1
Можем да използваме следната заявка, за да върнем информация за дублиращи се редове:
SELECT
DISTINCT PetId,
COUNT(*) AS "Count"
FROM Pets
GROUP BY PetId
ORDER BY PetId;
Резултат:
+---------+---------+ | PetId | Count | |---------+---------| | 1 | 2 | | 2 | 1 | | 3 | 1 | | 4 | 3 | +---------+---------+
Можем да разширим SELECT
списък, за да включите още колони, ако е необходимо:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY PetId;
Резултат:
+---------+-----------+-----------+---------+ | PetId | PetName | PetType | Count | |---------+-----------+-----------+---------| | 1 | Wag | Dog | 2 | | 2 | Scratch | Cat | 1 | | 3 | Tweet | Bird | 1 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+---------+
Ако таблицата има уникален идентификатор, можем просто да премахнем тази колона от заявката. Например, ако приемем, че PetId
колоната всъщност е колона с първичен ключ, която съдържа уникален идентификатор, бихме могли да изпълним следната заявка, за да върнем всички редове, които са дублирани, без да броим колоната с първичен ключ:
SELECT
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetName,
PetType
ORDER BY PetName;
Резултат:
+-----------+-----------+---------+ | PetName | PetType | Count | |-----------+-----------+---------| | Bark | Dog | 3 | | Scratch | Cat | 1 | | Tweet | Bird | 1 | | Wag | Dog | 2 | +-----------+-----------+---------+
Опция 2
Ако искаме да се върнат само действителните дублиращи се редове, можем да добавим HAVING
клауза:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
HAVING COUNT(*) > 1
ORDER BY PetId;
Резултат:
+---------+-----------+-----------+---------+ | PetId | PetName | PetType | Count | |---------+-----------+-----------+---------| | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+---------+
Опция 3
Друг начин да го направите е да използвате ROW_NUMBER()
функция с PARTITION BY
клауза за номериране на изхода на резултатния набор.
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets;
Резултат:
+---------+-----------+-----------+--------------+ | 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
клауза разделя резултатния набор, произведен от FROM
клауза в дялове, към които се прилага функцията. Когато посочим дялове за резултатния набор, всеки дял кара номерирането да започне отново (т.е. номерирането ще започне от 1 за първия ред във всеки дял).
Опция 4
Ако искаме да се връщат само излишни редове от съвпадащите дубликати, можем да използваме горната заявка като общ табличен израз, както следва:
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;
Резултат:
+---------+-----------+-----------+--------------+ | PetId | PetName | PetType | Row_Number | |---------+-----------+-----------+--------------| | 1 | Wag | Dog | 2 | | 4 | Bark | Dog | 2 | | 4 | Bark | Dog | 3 | +---------+-----------+-----------+--------------+
Едно от предимствата на това е, че можем да изтрием дублиращи се редове просто чрез превключване на SELECT *
до DELETE
(на последния ред).
Следователно можем да използваме горния код, за да видим кои редове ще бъдат изтрити и след това, когато сме доволни, че ще изтрием правилните редове, можем да го превключим на DELETE
изявление, за да ги изтриете.
Като това:
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;