Ето единадесет опции за връщане на дублиращи се редове в 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