sql >> Database >  >> RDS >> SQLite

11 manieren om dubbele rijen te vinden terwijl de primaire sleutel in SQLite wordt genegeerd

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 

  1. Wat is de beste manier om resultaten te pagineren in SQL Server?

  2. Hoe kan ik een query gebruiken met een tijdelijke aanduiding tussen aanhalingstekens? (perl / postgresql)

  3. Belang van het onderhouden van een HIPAA-compatibele database

  4. Extraheer de maand van een datum in PostgreSQL