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 |