Hier zijn elf opties voor het retourneren van dubbele rijen in SQLite wanneer die rijen een primaire sleutel of een andere unieke identificatiekolom hebben (maar u de primaire sleutel wilt negeren).
Dit betekent dat de dubbele rijen exact dezelfde waarden delen in alle kolommen, met uitzondering van hun primaire sleutel/unieke ID-kolom.
Voorbeeldgegevens
We gebruiken de volgende gegevens voor onze voorbeelden:
SELECT * FROM Dogs;
Resultaat:
DogId FirstName LastName ----- --------- -------- 1 Bark Smith 2 Bark Smith 3 Woof Jones 4 Ruff Robinson 5 Wag Johnson 6 Wag Johnson 7 Wag Johnson
De eerste twee rijen zijn duplicaten (behalve de DogId
kolom, de primaire sleutel van de tabel, en bevat een unieke waarde voor alle rijen). De laatste drie rijen zijn ook duplicaten (behalve de DogId
kolom).
De primaire sleutelkolom zorgt ervoor dat er geen dubbele rijen zijn, wat een goede gewoonte is in RDBMS'en, omdat primaire sleutels helpen de gegevensintegriteit af te dwingen. Maar omdat primaire sleutels dubbele rijen voorkomen, kunnen ze ons vermogen om dubbele rijen te vinden belemmeren.
In onze tabel hierboven is de kolom met de primaire sleutel een oplopend getal, en de waarde ervan heeft geen betekenis en is niet significant. We moeten die rij dus negeren als we duplicaten willen vinden in de andere kolommen.
Optie 1
We kunnen een query uitvoeren met de GROUP BY
clausule om de kolommen te groeperen op hun significante kolommen, gebruik dan de COUNT()
functie om het aantal identieke rijen terug te geven:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
ORDER BY Count DESC;
Resultaat:
FirstName LastName Count --------- -------- ----- Wag Johnson 3 Bark Smith 2 Ruff Robinson 1 Woof Jones 1
Hier hebben we de primaire sleutelkolom uitgesloten door deze uit onze zoekopdracht weg te laten. We hebben het ook gesorteerd op telling in aflopende volgorde, zodat de duplicaten eerst verschijnen.
Het resultaat vertelt ons dat er drie rijen zijn met Wag Johnson en twee rijen met Bark Smith. Dit zijn duplicaten (of drievoud in het geval van Wag Johnson). De andere twee rijen hebben geen dubbele rijen.
Optie 2
We kunnen de HAVING
. gebruiken clausule om niet-duplicaten van de uitvoer uit te sluiten:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1
ORDER BY Count DESC;
Resultaat:
FirstName LastName Count --------- -------- ----- Wag Johnson 3 Bark Smith 2
Optie 3
Hier is een voorbeeld van het controleren op duplicaten in aaneengeschakelde kolommen. In dit geval gebruiken we de DISTINCT
zoekwoord om verschillende waarden te krijgen, gebruik dan de COUNT()
functie om de telling terug te geven:
SELECT
DISTINCT FirstName || ' ' || LastName AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName || ' ' || LastName
ORDER BY Count DESC;
Resultaat:
DogName Count ------------- ----- Wag Johnson 3 Bark Smith 2 Woof Jones 1 Ruff Robinson 1
Optie 4
Standaard heeft elke rij in SQLite een speciale kolom, meestal de rowid
, die die rij in de tabel op unieke wijze identificeert. Tenzij het expliciet uit de tabel is verwijderd, kunt u dit gebruiken als een unieke identificatie voor elke rij.
We kunnen daarom de rowid
. gebruiken in onze vraag:
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
);
Resultaat:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag Johnson
We zouden de SELECT *
. kunnen vervangen met DELETE
om een ontdubbelingsoperatie op de tafel uit te voeren.
Merk op dat we de DogId
. hadden kunnen gebruiken kolom (onze primaire sleutel) in plaats van de rowid
als we wilden. Dat gezegd hebbende, de rowid
kan handig zijn als u de primaire sleutelkolom om de een of andere reden niet kunt gebruiken, of als de tabel geen primaire sleutel heeft.
Optie 5
Hier is nog een zoekopdracht die de rowid
. gebruikt :
SELECT * FROM Dogs
WHERE rowid > (
SELECT MIN(rowid) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
Resultaat:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag Johnson
Net als bij het vorige voorbeeld kunnen we de SELECT *
. vervangen met DELETE
om de dubbele rijen te verwijderen.
Optie 6
De twee rowid
bovenstaande opties zijn geweldig als u de primaire sleutel in uw zoekopdracht volledig moet negeren (of als u helemaal geen primaire sleutelkolom heeft). Maar zoals vermeld, is er nog steeds de mogelijkheid om rowid
te vervangen met de primaire sleutelkolom – in ons geval de DogId
kolom:
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
);
Resultaat:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag Johnson
Optie 7
En hier is de andere vraag met de rowid
vervangen door de DogId
kolom:
SELECT * FROM Dogs
WHERE DogId > (
SELECT MIN(DogId) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
Resultaat:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag Johnson
Optie 8
Een andere manier om dit te doen is door de ROW_NUMBER()
. te gebruiken vensterfunctie:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Resultaat:
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
De PARTITION
. gebruiken clausule resulteert in het toevoegen van een nieuwe kolom, met een rijnummer dat wordt verhoogd elke keer dat er een duplicaat is, maar opnieuw wordt ingesteld wanneer er een unieke rij is.
In dit geval groeperen we de resultaten niet, wat betekent dat we elke dubbele rij kunnen zien, inclusief de unieke ID-kolom.
Optie 9
We kunnen het vorige voorbeeld ook gebruiken als een algemene tabeluitdrukking in een grotere query:
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;
Resultaat:
DogId FirstName LastName Row_Number ----- --------- -------- ---------- 2 Bark Smith 2 6 Wag Johnson 2 7 Wag Johnson 3
Dat sluit niet-duplicaten uit van de uitvoer en sluit één rij van elk duplicaat uit van de uitvoer.
Optie 10
Hier is nog een manier om dezelfde uitvoer te krijgen als in het vorige voorbeeld:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Resultaat:
DogId FirstName LastName ----- --------- -------- 2 Bark Smith 6 Wag Johnson 7 Wag Johnson
Optie 11
Hier is nog een andere optie om duplicaten uit onze tabel te selecteren:
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
);
Resultaat:
DogId FirstName LastName DogId FirstName LastName ----- --------- -------- ----- --------- -------- 2 Bark Smith 1 Bark Smith 7 Wag Johnson 5 Wag Johnson 7 Wag Johnson 6 Wag Johnson