Ето единадесет опции за връщане на дублиращи се редове в SQLite, когато тези редове имат първичен ключ или някаква друга колона с уникален идентификатор (но искате да игнорирате първичния ключ).
Това означава, че дублираните редове споделят абсолютно едни и същи стойности във всички колони с изключение на техния първичен ключ/колоната с уникален идентификатор.
Примерни данни
Ще използваме следните данни за нашите примери:
SELECT * FROM Dogs;
Резултат:
DogId Име Фамилия----- --------- --------1 Bark Smith 2 Bark Smith 3 Woof Jones 4 Ruff Robinson5 Wag Johnson 6 Wag Johnson 7 Wag Johnson предварително>Първите два реда са дублирани (с изключение на
DogId
колона, която е първичен ключ на таблицата и съдържа уникална стойност във всички редове). Последните три реда също са дублирани (с изключение наDogId
колона).Колоната с първичен ключ гарантира, че няма дублиращи се редове, което е добра практика в RDBMS, тъй като първичните ключове помагат за налагане на целостта на данните. Но тъй като първичните ключове предотвратяват дублиране на редове, те имат потенциала да попречат на способността ни да намираме дубликати.
В нашата таблица по-горе колоната с първичен ключ е нарастващо число и стойността й няма значение и не е значима. Следователно трябва да игнорираме този ред, ако искаме да намерим дубликати в другите колони.
Опция 1
Можем да изпълним заявка с
GROUP BY
клауза, за да групирате колоните по значимите им колони, след това използвайтеCOUNT()
функция за връщане на броя на еднакви редове:SELECT FirstName, LastName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName, LastName ORDER BY Count DESC;
Резултат:
Първо име Фамилия Брой--------- --------- -----Уаг Джонсън 3 Барк Смит 2 Ръф Робинсън 1 Уф Джоунс 1Тук изключихме колоната с първичен ключ, като я пропуснахме от нашата заявка. Подредихме го и по брой в низходящ ред, така че дубликатите да се показват първи.
Резултатът ни казва, че има три реда, съдържащи Уаг Джонсън и два реда, съдържащи Барк Смит. Това са дубликати (или три екземпляра в случая на Уаг Джонсън). Другите два реда нямат дубликати.
Опция 2
Можем да използваме
HAVING
клауза за изключване на недублирани от изхода:SELECT FirstName, LastName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName, LastName HAVING COUNT(*) > 1 ORDER BY Count DESC;
Резултат:
Първо име Фамилия Брой--------- --------- -----Уаг Джонсън 3 Барк Смит 2Опция 3
Ето пример за проверка за дубликати на свързани колони. В този случай използваме
DISTINCT
ключова дума, за да получите различни стойности, след това използвайтеCOUNT()
функция за връщане на броя:SELECT DISTINCT FirstName || ' ' || LastName AS DogName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName || ' ' || LastName ORDER BY Count DESC;
Резултат:
Брой на имената на кучета------------ -----Ваг Джонсън 3 Барк Смит 2 Уф Джоунс 1 Ръф Робинсън 1Опция 4
По подразбиране всеки ред в SQLite има специална колона, обикновено наричана
rowid
, който уникално идентифицира този ред в таблицата. Освен ако не е премахнат изрично от таблицата, можете да го използвате като уникален идентификатор за всеки ред.Следователно можем да използваме
rowid
в нашата заявка: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 );
Резултат:
DogId Име Фамилия----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonБихме могли да заменим
SELECT *
сDELETE
за извършване на операция за премахване на дупки на масата.Имайте предвид, че можехме да използваме
DogId
колона (нашия първичен ключ) вместоrowid
ако искахме. Това каза,rowid
може да бъде полезно, ако по някаква причина не можете да използвате колоната с първичен ключ или ако таблицата няма първичен ключ.Опция 5
Ето още една заявка, която използва
rowid
:SELECT * FROM Dogs WHERE rowid > ( SELECT MIN(rowid) FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName );
Резултат:
DogId Име Фамилия----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonКакто в предишния пример, бихме могли да заменим
SELECT *
сDELETE
за да изтриете дублиращите се редове.Опция 6
Двата
rowid
опциите по-горе са страхотни, ако трябва напълно да игнорирате първичния ключ във вашата заявка (или ако изобщо нямате колона с първичен ключ). Въпреки това, както споменахме, все още има опция за замяна наrowid
с колоната с първичен ключ – в нашия случайDogId
колона: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 );
Резултат:
DogId Име Фамилия----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonОпция 7
А ето и другата заявка с
rowid
заменен отDogId
колона:SELECT * FROM Dogs WHERE DogId > ( SELECT MIN(DogId) FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName );
Резултат:
DogId Име Фамилия----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonОпция 8
Друг начин да го направите е да използвате
ROW_NUMBER()
функция на прозореца:SELECT *, ROW_NUMBER() OVER ( PARTITION BY FirstName, LastName ORDER BY FirstName, LastName ) AS Row_Number FROM Dogs;
Резултат:
DogId Име на фамилия Ред_Номер----- --------- -------- ----------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Използване на
PARTITION
клауза води до добавяне на нова колона с номер на ред, който се увеличава всеки път, когато има дубликат, но се нулира отново, когато има уникален ред.В този случай не групираме резултатите, което означава, че можем да видим всеки дублиран ред, включително колоната с уникален идентификатор.
Опция 9
Можем също да използваме предишния пример като общ табличен израз в по-голяма заявка:
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;
Резултат:
DogId Име на фамилия Ред_Номер----- --------- -------- ----------2 Bark Smith 2 6 Wag Johnson 2 7 Wag Johnson 3Това изключва недубликатите от изхода и изключва един ред от всеки дубликат от изхода.
Опция 10
Ето още един начин да получите същия изход като предишния пример:
SELECT * FROM Dogs WHERE DogId IN ( SELECT DogId FROM Dogs EXCEPT SELECT MIN(DogId) FROM Dogs GROUP BY FirstName, LastName );
Резултат:
DogId Име Фамилия----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonОпция 11
Ето още една опция за избор на дубликати от нашата таблица:
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 );
Резултат:
DogId FirstName Фамилия DogId FirstName Фамилия----- --------- -------- ----- --------- ----- ---2 Bark Smith 1 Bark Smith 7 Wag Johnson 5 Wag Johnson 7 Wag Johnson 6 Wag Johnson