Hier zijn elf opties voor het retourneren van dubbele rijen in Oracle Database wanneer die rijen een primaire sleutel of een andere unieke identificatiekolom hebben en u deze wilt negeren.
Voorbeeldgegevens
We gebruiken de volgende gegevens voor onze voorbeelden:
SELECT * FROM Dogs;
Resultaat:
HONDEN-ID | FIRSTNAME | Achternaam |
---|---|---|
1 | Bark | Smith |
2 | Bark | Smith |
3 | Inslag | Jones |
4 | Kemmel | Robinson |
5 | Kwispelen | Johnson |
6 | Kwispelen | Johnson |
7 | Kwispelen | Johnson |
De eerste twee rijen zijn duplicaten en de laatste drie rijen zijn duplicaten. De dubbele rijen delen exact dezelfde waarden in alle kolommen, met uitzondering van hun primaire sleutel/unieke ID-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 het feit dat primaire sleutels unieke waarden bevatten, betekent dat we die kolom moeten negeren bij het zoeken naar duplicaten.
In onze tabel hierboven is de primaire sleutelkolom een oplopend getal, en de waarde ervan heeft geen betekenis en is niet significant. We kunnen daarom de gegevens van die kolom negeren bij het zoeken naar duplicaten.
Optie 1
Dit is onze eerste optie voor het retourneren van duplicaten:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
ORDER BY Count DESC;
Resultaat:
FIRSTNAME | Achternaam | COUNT |
---|---|---|
Kwispelen | Johnson | 3 |
Borst | Smith | 2 |
Kemmel | Robinson | 1 |
Inslag | Jones | 1 |
Hier hebben we onze query gemaakt met de GROUP BY
clausule zodat de uitvoer wordt gegroepeerd op de relevante kolommen. We gebruikten ook de COUNT()
functie om het aantal identieke rijen te retourneren. En we hebben het gesorteerd 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
. toevoegen clausule toe aan ons vorige voorbeeld 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 | Achternaam | COUNT |
---|---|---|
Kwispelen | Johnson | 3 |
Borst | Smith | 2 |
Optie 3
We kunnen ook controleren op duplicaten op 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:
HONDENNAAM | COUNT |
---|---|
Wag Johnson | 3 |
Bark Smith | 2 |
Ruff Robinson | 1 |
Woef Jones | 1 |
Optie 4
Elke rij in Oracle heeft een rowid
pseudokolom die het adres van de rij retourneert. De rowid
is een unieke id voor rijen in de tabel, en gewoonlijk identificeert de waarde ervan een rij in de database op unieke wijze (hoewel het belangrijk is op te merken dat rijen in verschillende tabellen die samen in hetzelfde cluster zijn opgeslagen dezelfde rowid ).
Hoe dan ook, we kunnen een query maken die de rowid
. gebruikt als we willen:
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:
HONDEN-ID | FIRSTNAME | Achternaam |
---|---|---|
2 | Bark | Smith |
6 | Kwispelen | Johnson |
7 | Kwispelen | Johnson |
We zouden de SELECT *
. kunnen vervangen met VERWIJDEREN
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:
HONDEN-ID | FIRSTNAME | Achternaam |
---|---|---|
2 | Bark | Smith |
6 | Kwispelen | Johnson |
7 | Kwispelen | Johnson |
Net als bij het vorige voorbeeld kunnen we de SELECT *
. vervangen met VERWIJDEREN
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:
HONDEN-ID | FIRSTNAME | Achternaam |
---|---|---|
2 | Bark | Smith |
6 | Kwispelen | Johnson |
7 | Kwispelen | 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:
HONDEN-ID | FIRSTNAME | Achternaam |
---|---|---|
2 | Bark | Smith |
6 | Kwispelen | Johnson |
7 | Kwispelen | Johnson |
Optie 8
Een andere manier om duplicaten te vinden is door de ROW_NUMBER()
. te gebruiken vensterfunctie:
SELECT
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs;
Resultaat:
HONDEN-ID | FIRSTNAME | Achternaam | ROW_NUM |
---|---|---|---|
1 | Bark | Smith | 1 |
2 | Bark | Smith | 2 |
4 | Kemmel | Robinson | 1 |
7 | Kwispelen | Johnson | 1 |
5 | Kwispelen | Johnson | 2 |
6 | Kwispelen | Johnson | 3 |
3 | Inslag | Jones | 1 |
De PARTITIE
. 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
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs
)
SELECT * FROM cte WHERE row_num <> 1;
Resultaat:
HONDEN-ID | FIRSTNAME | Achternaam | ROW_NUM |
---|---|---|---|
2 | Bark | Smith | 2 |
5 | Kwispelen | Johnson | 2 |
6 | Kwispelen | Johnson | 3 |
Die zoekopdracht 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
MINUS SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Resultaat:
HONDEN-ID | FIRSTNAME | Achternaam |
---|---|---|
2 | Bark | Smith |
6 | Kwispelen | Johnson |
7 | Kwispelen | Johnson |
Dit voorbeeld gebruikt Oracle's MINUS
operator, die alleen unieke rijen retourneert die worden geretourneerd door de eerste query, maar niet door de tweede.
De MIN
operator is vergelijkbaar met de BEHALVE
operator in andere DBMS'en, zoals SQL Server, MariaDB, PostgreSQL en SQLite.
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:
HONDEN-ID | FIRSTNAME | Achternaam | HONDEN-ID | FIRSTNAME | Achternaam |
---|---|---|---|---|---|
2 | Bark | Smith | 1 | Bark | Smith |
7 | Kwispelen | Johnson | 5 | Kwispelen | Johnson |
7 | Kwispelen | Johnson | 6 | Kwispelen | Johnson |