Следните примери връщат дублиращи се редове от таблица на Oracle Database.
Примерни данни
Да предположим, че имаме таблица със следните данни:
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
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
Групирахме редовете по всички колони и върнахме броя на редовете за всяка група. Всеки ред с брой по-голям от 1 е дубликат.
Можем да го подредим по брой в низходящ ред, така че редовете с най-много дубликати да се показват първи:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY Count(*) DESC;
Резултат:
PETID PETNAME PETTYPE Count 4 Bark Dog 3 1 Wag Dog 2 2 Scratch Cat 1 3 Tweet Bird 1
Опция 2
Ако искаме само изброените дублиращи се редове, можем да използваме HAVING
клауза за връщане само на редове с брой по-голям от 1:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC;
Резултат:
PETID PETNAME PETTYPE Count 4 Bark Dog 3 1 Wag Dog 2
Опция 3
Друга възможност е да използвате ROW_NUMBER()
функция на прозореца:
SELECT
PetId,
PetName,
PetType,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS rn
FROM Pets;
Резултат:
PETID PETNAME PETTYPE RN 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
PetId,
PetName,
PetType,
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
Това връща само излишните редове от съответстващите дубликати. Така че, ако има два еднакви реда, той връща един от тях. Ако има три еднакви реда, той връща два и т.н.
Опция 5
Като се има предвид, че нашата таблица не съдържа колона с първичен ключ, можем да се възползваме от rowid
на Oracle псевдоколона:
SELECT * FROM Pets
WHERE EXISTS (
SELECT 1 FROM Pets p2
WHERE Pets.PetName = p2.PetName
AND Pets.PetType = p2.PetType
AND Pets.rowid > p2.rowid
);
Резултат:
PETID PETNAME PETTYPE 1 Wag Dog 4 Bark Dog 4 Bark Dog
Начинът, по който това работи, е, че всеки ред в база данни на Oracle има rowid
псевдоколона, която връща адреса на реда. rowid
е уникален идентификатор за редове в таблицата и обикновено неговата стойност уникално идентифицира ред в базата данни. Важно е обаче да се отбележи, че редовете в различни таблици, които се съхраняват заедно в един и същ клъстер, могат да имат един и същ rowid
.
Едно от предимствата на горния пример е, че можем да заменим SELECT *
с DELETE
за да премахнете измамата на масата.
Опция 6
И накрая, ето още една опция, която използва rowid
псевдоколона:
SELECT * FROM Pets
WHERE rowid > (
SELECT MIN(rowid) FROM Pets p2
WHERE Pets.PetName = p2.PetName
AND Pets.PetType = p2.PetType
);
Резултат:
PETID PETNAME PETTYPE 1 Wag Dog 4 Bark Dog 4 Bark Dog
Същият резултат като предишния пример.
Както в предишния пример, можем да заменим SELECT *
с DELETE
за да премахнете дублиращи се редове от таблицата.