Het extraheren van unieke records in SQL is een cruciale taak geworden met de massale overstap van organisaties naar het opslaan van multidimensionale gegevens. Soms is het nodig om unieke rijen op basis van een combinatie van verschillende kolommen weer te geven, soms slechts op één sleutel.
Achtergrond van de vraag:
De eerste versies van SQL boden alleen DISTINCT aan voor het filteren van duplicaten. Daarna verschenen er structurele technieken, waaronder GROUP BY voor aggregaties op unieke waardeparen en venstervarianten zoals ROW_NUMBER() voor flexibele scenario's bij het werken met duplicaten, bijvoorbeeld: selectie op de 'laatste' of 'eerste' record.
Probleem:
DISTINCT werkt alleen op het niveau van de velden in SELECT, terwijl GROUP BY aggregaties vereist. Venstervarianten bieden geavanceerde logica, maar het gebruik ervan leidt vaak tot fouten, als de volgorde van rijselectie niet goed wordt nagedacht. Ontwikkelaars verwarren vaak deze benaderingen, wat leidt tot onjuiste resultaten.
Oplossing:
Voorbeeldcode:
Een laatste record van bestellingen per klant ophalen:
WITH OrdersRank AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) as rn FROM Orders ) SELECT * FROM OrdersRank WHERE rn = 1;
Kernpunten:
Is het mogelijk om DISTINCT te gebruiken met aggregatiefuncties zonder GROUP BY?
Nee, aggregatiefuncties vereisen groepering, anders is er een syntaxisfout.
SELECT COUNT(DISTINCT CustomerID) -- correct SELECT SUM(Amount), DISTINCT CustomerID -- fout!
Wat gebeurt er als niet alle niet-aggregatievelden uit SELECT in GROUP BY worden opgegeven?
Dit veroorzaakt een fout in de meeste DBMS: alle velden in SELECT, behalve de aggregaten, moeten in GROUP BY worden vermeld.
Kan men duplicaten "verwijderen" met behulp van venstervarianten zonder subquery?
Nee: het gebruik van ROW_NUMBER() binnen dezelfde SELECT filtert niet automatisch "herhalingen", een externe query is nodig om de gewenste rijen te selecteren.
DISTINCT geselecteerd op alle kolommen voor een tabel van 20 miljoen rijen: de query werkte uren, het resultaat was een time-out of een daling van de databaseprestaties.
Voordelen:
Nadelen:
Venstervarianten gebruikt: alleen de benodigde laatste registratie per klant in milliseconden verkregen; eerdere en herhalende werden niet geladen.
Voordelen:
Nadelen: