Oto jedenaście opcji zwracania zduplikowanych wierszy w Oracle Database, gdy te wiersze mają klucz podstawowy lub inną kolumnę unikatowego identyfikatora i chcesz ją zignorować.
Przykładowe dane
W naszych przykładach użyjemy następujących danych:
SELECT * FROM Dogs;
Wynik:
DOGI | FIRSTNAME | NAZWISKO |
---|---|---|
1 | Kora | Kowalski |
2 | Kora | Kowalski |
3 | Huu | Jones |
4 | kryza | Robinson |
5 | Wag | Johnson |
6 | Wag | Johnson |
7 | Wag | Johnson |
Pierwsze dwa wiersze są duplikatami, a ostatnie trzy wiersze są duplikatami. Zduplikowane wiersze mają dokładnie te same wartości we wszystkich kolumnach z wyjątkiem ich kolumny klucza podstawowego/unikalnego identyfikatora.
Kolumna klucza podstawowego zapewnia, że nie ma zduplikowanych wierszy, co jest dobrą praktyką w systemach RDBMS, ponieważ klucze podstawowe pomagają wymusić integralność danych. Jednak fakt, że klucze podstawowe zawierają unikatowe wartości, oznacza, że musimy zignorować tę kolumnę podczas wyszukiwania duplikatów.
W naszej tabeli powyżej kolumna klucza podstawowego jest liczbą rosnącą, a jej wartość nie ma znaczenia i nie jest istotna. Możemy zatem zignorować dane tej kolumny podczas wyszukiwania duplikatów.
Opcja 1
Oto nasza pierwsza opcja zwracania duplikatów:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
ORDER BY Count DESC;
Wynik:
FIRSTNAME | NAZWISKO | LICZBA |
---|---|---|
Wag | Johnson | 3 |
Kora | Kowalski | 2 |
kryza | Robinson | 1 |
Hał | Jones | 1 |
Tutaj skonstruowaliśmy nasze zapytanie za pomocą GROUP BY
tak, aby dane wyjściowe były pogrupowane według odpowiednich kolumn. Użyliśmy również COUNT()
funkcja zwracająca liczbę identycznych wierszy. Uporządkowaliśmy je według liczby w porządku malejącym, aby duplikaty pojawiły się jako pierwsze.
Wynik mówi nam, że istnieją trzy wiersze zawierające Wag Johnson i dwa wiersze zawierające Bark Smith. Są to duplikaty (lub trzy egzemplarze w przypadku Wag Johnson). Pozostałe dwa wiersze nie mają żadnych duplikatów.
Opcja 2
Możemy dodać HAVING
klauzula do naszego poprzedniego przykładu, aby wykluczyć nieduplikaty z danych wyjściowych:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1
ORDER BY Count DESC;
Wynik:
FIRSTNAME | NAZWISKO | LICZBA |
---|---|---|
Wag | Johnson | 3 |
Kora | Kowalski | 2 |
Opcja 3
Możemy również sprawdzić duplikaty w połączonych kolumnach. W tym przypadku używamy DISTINCT
słowa kluczowego, aby uzyskać różne wartości, a następnie użyj COUNT()
funkcja zwracająca liczbę:
SELECT
DISTINCT FirstName || ' ' || LastName AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName || ' ' || LastName
ORDER BY Count DESC;
Wynik:
NAZWA PSA | LICZBA |
---|---|
Wag Johnson | 3 |
Kora Kowal | 2 |
Ruff Robinson | 1 |
Hau Jones | 1 |
Opcja 4
Każdy wiersz w 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 (chociaż należy pamiętać, że wiersze w różnych tabelach, które są przechowywane razem w tym samym klastrze, mogą mieć ten sam rowid ).
W każdym razie możemy skonstruować zapytanie, które używa rowid
jeśli chcemy:
SELECT * FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.rowid > d2.rowid
);
Wynik:
DOGI | FIRSTNAME | NAZWISKO |
---|---|---|
2 | Kora | Kowalski |
6 | Wag | Johnson |
7 | Wag | Johnson |
Moglibyśmy zastąpić SELECT *
z USUŃ
aby wykonać operację usuwania duplikatów na stole.
Zauważ, że mogliśmy użyć DogId
kolumna (nasz klucz podstawowy) zamiast rowid
gdybyśmy chcieli. To powiedziawszy, rowid
może być przydatne, jeśli z jakiegoś powodu nie możesz użyć kolumny klucza podstawowego lub jeśli tabela nie ma klucza podstawowego.
Opcja 5
Oto kolejne zapytanie, które używa rowid
:
SELECT * FROM Dogs
WHERE rowid > (
SELECT MIN(rowid) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
Wynik:
DOGI | FIRSTNAME | NAZWISKO |
---|---|---|
2 | Kora | Kowalski |
6 | Wag | Johnson |
7 | Wag | Johnson |
Podobnie jak w poprzednim przykładzie, możemy zastąpić SELECT *
z USUŃ
aby usunąć zduplikowane wiersze.
Opcja 6
Dwa rowid
powyższe opcje są świetne, jeśli musisz całkowicie zignorować klucz podstawowy w zapytaniu (lub jeśli w ogóle nie masz kolumny klucza podstawowego). Jednak jak wspomniano, nadal istnieje możliwość zastąpienia rowid
z kolumną klucza podstawowego – w naszym przypadku DogId
kolumna:
SELECT * FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.DogId > d2.DogId
);
Wynik:
DOGI | FIRSTNAME | NAZWISKO |
---|---|---|
2 | Kora | Kowalski |
6 | Wag | Johnson |
7 | Wag | Johnson |
Opcja 7
A oto inne zapytanie z rowid
zastąpione przez DogId
kolumna:
SELECT * FROM Dogs
WHERE DogId > (
SELECT MIN(DogId) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
Wynik:
DOGI | FIRSTNAME | NAZWISKO |
---|---|---|
2 | Kora | Kowalski |
6 | Wag | Johnson |
7 | Wag | Johnson |
Opcja 8
Innym sposobem na znalezienie duplikatów jest użycie ROW_NUMBER()
funkcja okna:
SELECT
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs;
Wynik:
DOGI | FIRSTNAME | NAZWISKO | ROW_NUM |
---|---|---|---|
1 | Kora | Kowalski | 1 |
2 | Kora | Kowalski | 2 |
4 | kryza | Robinson | 1 |
7 | Wag | Johnson | 1 |
5 | Wag | Johnson | 2 |
6 | Wag | Johnson | 3 |
3 | Huu | Jones | 1 |
Korzystanie z PARTYCJI
klauzula powoduje dodanie nowej kolumny z numerem wiersza, który zwiększa się za każdym razem, gdy pojawia się duplikat, ale resetuje się ponownie, gdy istnieje unikalny wiersz.
W tym przypadku nie grupujemy wyników, co oznacza, że możemy zobaczyć każdy zduplikowany wiersz, w tym jego kolumnę z unikalnym identyfikatorem.
Opcja 9
Możemy również użyć poprzedniego przykładu jako wspólnego wyrażenia tabelowego w większym zapytaniu:
WITH cte AS
(
SELECT
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs
)
SELECT * FROM cte WHERE row_num <> 1;
Wynik:
DOGI | FIRSTNAME | NAZWISKO | ROW_NUM |
---|---|---|---|
2 | Kora | Kowalski | 2 |
5 | Wag | Johnson | 2 |
6 | Wag | Johnson | 3 |
To zapytanie wyklucza nieduplikaty z danych wyjściowych i wyklucza jeden wiersz każdego duplikatu z danych wyjściowych.
Opcja 10
Oto inny sposób na uzyskanie tego samego wyniku, co w poprzednim przykładzie:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
MINUS SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Wynik:
DOGI | FIRSTNAME | NAZWISKO |
---|---|---|
2 | Kora | Kowalski |
6 | Wag | Johnson |
7 | Wag | Johnson |
W tym przykładzie użyto MINUS
Oracle operator, który zwraca tylko unikalne wiersze zwrócone przez pierwsze zapytanie, ale nie przez drugie.
MINUS
operator jest podobny do EXCEPT
operatora w innych DBMS, takich jak SQL Server, MariaDB, PostgreSQL i SQLite.
Opcja 11
Oto kolejna opcja wyboru duplikatów z naszej tabeli:
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
);
Wynik:
DOGI | FIRSTNAME | NAZWISKO | DOGI | FIRSTNAME | NAZWISKO |
---|---|---|---|---|---|
2 | Kora | Kowalski | 1 | Kora | Kowalski |
7 | Wag | Johnson | 5 | Wag | Johnson |
7 | Wag | Johnson | 6 | Wag | Johnson |