Zde je jedenáct možností pro vrácení duplicitních řádků v SQLite, když tyto řádky mají primární klíč nebo jiný sloupec jedinečného identifikátoru (ale chcete ignorovat primární klíč).
To znamená, že duplicitní řádky sdílejí přesně stejné hodnoty ve všech sloupcích s výjimkou jejich primárního klíče/sloupce jedinečného ID.
Ukázková data
Pro naše příklady použijeme následující data:
SELECT * FROM Dogs;
Výsledek:
DogId Jméno Příjmení----- --------- --------1 Bark Smith 2 Bark Smith 3 Woof Jones 4 Ruff Robinson5 Wag Johnson 6 Wag Johnson 7 Wag JohnsonPrvní dva řádky jsou duplikáty (kromě
DogId
sloupec, který je primárním klíčem tabulky a obsahuje jedinečnou hodnotu ve všech řádcích). Poslední tři řádky jsou také duplikáty (kroměDogId
sloupec).Sloupec primárního klíče zajišťuje, že neexistují žádné duplicitní řádky, což je dobrá praxe v RDBMS, protože primární klíče pomáhají zajistit integritu dat. Ale protože primární klíče zabraňují duplicitním řádkům, mohou narušit naši schopnost najít duplikáty.
V naší tabulce výše je sloupec primárního klíče rostoucí číslo a jeho hodnota nemá žádný význam a není významná. Pokud tedy chceme najít duplikáty v ostatních sloupcích, musíme tento řádek ignorovat.
Možnost 1
Můžeme spustit dotaz pomocí
GROUP BY
klauzule k seskupení sloupců podle jejich významných sloupců, pak použijteCOUNT()
funkce, která vrátí počet identických řádků:SELECT FirstName, LastName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName, LastName ORDER BY Count DESC;
Výsledek:
Jméno Příjmení Počet--------- -------- -----Wag Johnson 3 Bark Smith 2 Ruff Robinson 1 Woof Jones 1Zde jsme vyloučili sloupec primárního klíče jeho vynecháním z našeho dotazu. Také jsme to seřadili podle počtu v sestupném pořadí, aby se jako první objevily duplikáty.
Výsledek nám říká, že existují tři řádky obsahující Wag Johnson a dva řádky obsahující Bark Smith. Jedná se o duplikáty (nebo triplikáty v případě Waga Johnsona). Další dva řádky nemají žádné duplikáty.
Možnost 2
Můžeme použít
HAVING
klauzule k vyloučení neduplikátů z výstupu:SELECT FirstName, LastName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName, LastName HAVING COUNT(*) > 1 ORDER BY Count DESC;
Výsledek:
Jméno Příjmení Počet--------- -------- -----Wag Johnson 3 Bark Smith 2Možnost 3
Zde je příklad kontroly duplikátů ve zřetězených sloupcích. V tomto případě použijeme
DISTINCT
klíčové slovo, abyste získali odlišné hodnoty, pak použijteCOUNT()
funkce, která vrátí počet:SELECT DISTINCT FirstName || ' ' || LastName AS DogName, COUNT(*) AS Count FROM Dogs GROUP BY FirstName || ' ' || LastName ORDER BY Count DESC;
Výsledek:
Počet jmen psů------------- -----Wag Johnson 3 Bark Smith 2 Woof Jones 1 Ruff Robinson 1Možnost 4
Ve výchozím nastavení má každý řádek v SQLite speciální sloupec, který se obvykle nazývá
rowid
, který jednoznačně identifikuje daný řádek v tabulce. Pokud nebyl explicitně odstraněn z tabulky, můžete jej použít jako jedinečný identifikátor pro každý řádek.Můžeme tedy použít
rowid
v našem dotazu: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 );
Výsledek:
DogId FirstName Příjmení----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonMohli bychom nahradit
SELECT *
pomocíDELETE
k provedení operace odstranění duplikace na stole.Všimněte si, že jsme mohli použít
DogId
(náš primární klíč) namístorowid
kdybychom chtěli. To znamená, žerowid
může být užitečné, pokud z nějakého důvodu nemůžete použít sloupec primárního klíče nebo pokud tabulka primární klíč nemá.Možnost 5
Zde je další dotaz, který používá
rowid
:SELECT * FROM Dogs WHERE rowid > ( SELECT MIN(rowid) FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName );
Výsledek:
DogId FirstName Příjmení----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonStejně jako v předchozím příkladu bychom mohli nahradit
SELECT *
pomocíDELETE
k odstranění duplicitních řádků.Možnost 6
Dva
rowid
výše uvedené možnosti jsou skvělé, pokud musíte primární klíč v dotazu zcela ignorovat (nebo pokud sloupec primárního klíče vůbec nemáte). Jak však bylo zmíněno, stále existuje možnost nahraditrowid
se sloupcem primárního klíče – v našem případěDogId
sloupec: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 );
Výsledek:
DogId FirstName Příjmení----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonMožnost 7
A zde je další dotaz s
rowid
nahrazenoDogId
sloupec:SELECT * FROM Dogs WHERE DogId > ( SELECT MIN(DogId) FROM Dogs d2 WHERE Dogs.FirstName = d2.FirstName AND Dogs.LastName = d2.LastName );
Výsledek:
DogId FirstName Příjmení----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonMožnost 8
Dalším způsobem, jak to udělat, je použít
ROW_NUMBER()
funkce okna:SELECT *, ROW_NUMBER() OVER ( PARTITION BY FirstName, LastName ORDER BY FirstName, LastName ) AS Row_Number FROM Dogs;
Výsledek:
DogId Jméno Příjmení 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 1Pomocí
PARTITION
klauzule má za následek přidání nového sloupce s číslem řádku, které se zvýší pokaždé, když existuje duplikát, ale znovu se resetuje, když existuje jedinečný řádek.V tomto případě výsledky neseskupujeme, což znamená, že můžeme vidět každý duplicitní řádek, včetně sloupce s jedinečným identifikátorem.
Možnost 9
Předchozí příklad můžeme také použít jako běžný tabulkový výraz ve větším dotazu:
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;
Výsledek:
DogId Jméno Příjmení Row_Number----- --------- -------- ----------2 Bark Smith 2 6 Wag Johnson 2 7 Wag Johnson 3To vylučuje neduplikáty z výstupu a vylučuje jeden řádek každého duplikátu z výstupu.
Možnost 10
Zde je další způsob, jak získat stejný výstup jako v předchozím příkladu:
SELECT * FROM Dogs WHERE DogId IN ( SELECT DogId FROM Dogs EXCEPT SELECT MIN(DogId) FROM Dogs GROUP BY FirstName, LastName );
Výsledek:
DogId FirstName Příjmení----- --------- --------2 Bark Smith 6 Wag Johnson 7 Wag JohnsonMožnost 11
Zde je další možnost výběru duplikátů z naší tabulky:
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 );
Výsledek:
DogId Jméno Příjmení DogId Jméno Příjmení----- --------- -------- ----- --------- ----- ---2 Bark Smith 1 Bark Smith 7 Wag Johnson 5 Wag Johnson 7 Wag Johnson 6 Wag Johnson