Oto jedenaście opcji zwracania zduplikowanych wierszy w SQLite, gdy te wiersze mają klucz podstawowy lub inną kolumnę unikatowego identyfikatora (ale chcesz zignorować klucz podstawowy).
Oznacza to, że zduplikowane wiersze mają dokładnie te same wartości we wszystkich kolumnach z wyjątkiem kolumny klucza podstawowego/unikalnego identyfikatora.
Przykładowe dane
W naszych przykładach użyjemy następujących danych:
SELECT * FROM Dogs;
Wynik:
DogId FirstName LastName ----- --------- -------- 1 Bark Smith 2 Bark Smith 3 Woof Jones 4 Ruff Robinson 5 Wag Johnson 6 Wag Johnson 7 Wag Johnson
Pierwsze dwa wiersze są duplikatami (z wyjątkiem DogId
kolumna, która jest kluczem podstawowym tabeli i zawiera unikatową wartość we wszystkich wierszach). Ostatnie trzy wiersze również są duplikatami (z wyjątkiem DogId
kolumna).
Kolumna klucza podstawowego zapewnia, że nie ma zduplikowanych wierszy, co jest dobrą praktyką w systemach RDBMS, ponieważ klucze podstawowe pomagają wymusić integralność danych. Ale ponieważ klucze podstawowe zapobiegają duplikowaniu wierszy, mogą one potencjalnie zakłócać naszą zdolność do znajdowania duplikatów.
W naszej tabeli powyżej kolumna klucza podstawowego jest liczbą rosnącą, a jej wartość nie ma znaczenia i nie jest istotna. Dlatego musimy zignorować ten wiersz, jeśli chcemy znaleźć duplikaty w innych kolumnach.
Opcja 1
Możemy uruchomić zapytanie za pomocą GROUP BY
klauzula, aby pogrupować kolumny według ich znaczących kolumn, a następnie użyj COUNT()
funkcja zwracająca liczbę identycznych wierszy:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
ORDER BY Count DESC;
Wynik:
FirstName LastName Count --------- -------- ----- Wag Johnson 3 Bark Smith 2 Ruff Robinson 1 Woof Jones 1
Tutaj wykluczyliśmy kolumnę klucza podstawowego, pomijając ją w naszym zapytaniu. Uporządkowaliśmy je również według liczby w porządku malejącym, tak aby duplikaty pojawiał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 użyć HAVING
klauzula wykluczająca 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 LastName Count --------- -------- ----- Wag Johnson 3 Bark Smith 2
Opcja 3
Oto przykład sprawdzania duplikatów 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:
DogName Count ------------- ----- Wag Johnson 3 Bark Smith 2 Woof Jones 1 Ruff Robinson 1
Opcja 4
Domyślnie każdy wiersz w SQLite ma specjalną kolumnę, zwykle nazywaną rowid
, który jednoznacznie identyfikuje ten wiersz w tabeli. O ile nie został wyraźnie usunięty z tabeli, możesz użyć go jako unikalnego identyfikatora dla każdego wiersza.
Możemy zatem użyć rowid
w naszym zapytaniu:
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:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag Johnson
Moglibyśmy zastąpić SELECT *
z DELETE
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:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag Johnson
Podobnie jak w poprzednim przykładzie, możemy zastąpić SELECT *
z DELETE
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:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 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:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag Johnson
Opcja 8
Innym sposobem na to jest użycie ROW_NUMBER()
funkcja okna:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Wynik:
DogId FirstName LastName Row_Number ----- --------- -------- ---------- 1 Bark Smith 1 2 Bark Smith 2 4 Ruff Robinson 1 5 Wag Johnson 1 6 Wag Johnson 2 7 Wag Johnson 3 3 Woof Jones 1
Korzystanie z PARTITION
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
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs
)
SELECT * FROM cte WHERE Row_Number <> 1;
Wynik:
DogId FirstName LastName Row_Number ----- --------- -------- ---------- 2 Bark Smith 2 6 Wag Johnson 2 7 Wag Johnson 3
To 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
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Wynik:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag Johnson
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:
DogId FirstName LastName DogId FirstName LastName ----- --------- -------- ----- --------- -------- 2 Bark Smith 1 Bark Smith 7 Wag Johnson 5 Wag Johnson 7 Wag Johnson 6 Wag Johnson