Poniższe przykłady zwracają zduplikowane wiersze z tabeli bazy danych Oracle.
Przykładowe dane
Załóżmy, że mamy tabelę z następującymi danymi:
SELECT * FROM Pets;
Wynik:
PetId PetName PetType ----- ------- ------- 1 Wag Dog 1 Wag Dog 2 Scratch Cat 3 Tweet Bird 4 Bark Dog 4 Bark Dog 4 Bark Dog
Pierwsze dwa wiersze są duplikatami, podobnie jak ostatnie trzy wiersze. W takim przypadku zduplikowane wiersze zawierają zduplikowane wartości we wszystkich kolumnach, w tym w kolumnie ID.
Opcja 1
Możemy użyć następującego zapytania, aby zobaczyć, ile wierszy jest duplikatami:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY PetId;
Wynik:
PETID PETNAME PETTYPE Count 1 Wag Dog 2 2 Scratch Cat 1 3 Tweet Bird 1 4 Bark Dog 3
Pogrupowaliśmy wiersze według wszystkich kolumn i zwróciliśmy liczbę wierszy każdej grupy. Każdy wiersz z liczbą większą niż 1 jest duplikatem.
Możemy uporządkować to według liczby w porządku malejącym, tak aby wiersze z największą liczbą duplikatów pojawiły się jako pierwsze:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY Count(*) DESC;
Wynik:
PETID PETNAME PETTYPE Count 4 Bark Dog 3 1 Wag Dog 2 2 Scratch Cat 1 3 Tweet Bird 1
Opcja 2
Jeśli chcemy wyświetlić tylko zduplikowane wiersze, możemy użyć HAVING
klauzula zwracająca tylko wiersze o liczbie większej niż 1:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC;
Wynik:
PETID PETNAME PETTYPE Count 4 Bark Dog 3 1 Wag Dog 2
Opcja 3
Inną opcją jest użycie ROW_NUMBER()
funkcja okna:
SELECT
PetId,
PetName,
PetType,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS rn
FROM Pets;
Wynik:
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
klauzula dzieli zbiór wyników utworzony przez FROM
klauzuli na przegrody, do których funkcja jest stosowana. Kiedy określamy partycje dla zestawu wyników, każda partycja powoduje, że numeracja zaczyna się od nowa (tj. numeracja rozpocznie się od 1 dla pierwszego wiersza w każdej partycji).
Opcja 4
Możemy użyć powyższego zapytania jako wspólnego wyrażenia tabelowego:
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;
Wynik:
PETID PETNAME PETTYPE ROW_NUMBER 1 Wag Dog 2 4 Bark Dog 2 4 Bark Dog 3
Zwraca to tylko nadmiarowe wiersze z pasujących duplikatów. Więc jeśli są dwa identyczne wiersze, zwraca jeden z nich. Jeśli są trzy identyczne wiersze, zwraca dwa i tak dalej.
Opcja 5
Biorąc pod uwagę, że nasza tabela nie zawiera kolumny klucza podstawowego, możemy skorzystać z rowid
firmy Oracle pseudokolumna:
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
);
Wynik:
PETID PETNAME PETTYPE 1 Wag Dog 4 Bark Dog 4 Bark Dog
Działa to tak, że każdy wiersz w bazie danych Oracle ma rowid
pseudokolumna, która zwraca adres wiersza. rowid
jest unikalnym identyfikatorem wierszy w tabeli i zwykle jego wartość jednoznacznie identyfikuje wiersz w bazie danych. Należy jednak pamiętać, że wiersze w różnych tabelach, które są przechowywane razem w tym samym klastrze, mogą mieć ten sam rowid
.
Jedną z zalet powyższego przykładu jest to, że możemy zastąpić SELECT *
z DELETE
w celu usunięcia duplikatów tabeli.
Opcja 6
I na koniec, oto kolejna opcja, która używa rowid
pseudokolumna:
SELECT * FROM Pets
WHERE rowid > (
SELECT MIN(rowid) FROM Pets p2
WHERE Pets.PetName = p2.PetName
AND Pets.PetType = p2.PetType
);
Wynik:
PETID PETNAME PETTYPE 1 Wag Dog 4 Bark Dog 4 Bark Dog
Taki sam wynik jak w poprzednim przykładzie.
Podobnie jak w poprzednim przykładzie, możemy zastąpić SELECT *
z DELETE
w celu usunięcia zduplikowanych wierszy z tabeli.