Paginering wordt vaak gebruikt in toepassingen waar de gebruiker kan klikken op Vorige /Volgende om door de pagina's te navigeren die deel uitmaken van de resultaten, of klik op een paginanummer om direct naar een specifieke pagina te gaan.
Wanneer u query's uitvoert in SQL Server, kunt u de resultaten pagineren met behulp van de OFFSET
en FETCH
argumenten van de ORDER BY
clausule. Deze argumenten zijn geïntroduceerd in SQL Server 2012, daarom kunt u deze techniek gebruiken als u SQL Server 2012 of hoger hebt.
In deze context is paginering de plaats waar u de queryresultaten in kleinere stukken verdeelt, waarbij elk stuk verdergaat waar het vorige eindigde. Als een query bijvoorbeeld 1000 rijen retourneert, kunt u ze pagineren zodat ze worden geretourneerd in groepen van 100. Een toepassing kan het paginanummer en de paginagrootte doorgeven aan SQL Server, en SQL Server kan deze vervolgens gebruiken om alleen de gegevens voor de opgevraagde pagina.
Voorbeeld 1 – Geen paginering
Laten we eerst een query uitvoeren die alle rijen in een tabel retourneert:
SELECT * FROM Genres ORDER BY GenreId;
Resultaat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | | 7 | Rap | | 8 | Punk | +-----------+---------+
Dit voorbeeld gebruikt geen paginering - alle resultaten worden weergegeven.
Deze resultatenset is zo klein dat paginering normaal gesproken niet nodig is, maar laten we hem voor de doeleinden van dit artikel pagineren.
Voorbeeld 2 – Toon de eerste 3 resultaten
In dit voorbeeld worden de eerste drie resultaten weergegeven:
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;
Resultaat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
In dit geval specificeer ik dat de resultaten moeten beginnen bij het eerste resultaat en de volgende drie rijen moeten weergeven. Dit wordt gedaan met behulp van het volgende:
OFFSET 0 ROWS
specificeert dat er geen offset mag zijn (een offset van nul).FETCH NEXT 3 ROWS ONLY
krijgt de volgende drie rijen van de offset. Aangezien ik een offset van nul heb opgegeven, worden de eerste drie rijen opgehaald.
Als we alleen de top 3 resultaten wilden, hadden we hetzelfde resultaat kunnen bereiken door de TOP
te gebruiken. clausule in plaats van de offset- en fetch-waarden op te geven. Dit zou ons echter niet in staat hebben gesteld om het volgende deel te doen.
Voorbeeld 3 – Toon de volgende 3 resultaten
Laten we nu de volgende drie resultaten weergeven:
SELECT * FROM Genres ORDER BY GenreId OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY;
Resultaat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+
Dus het enige dat ik veranderde was de offset.
De offset- en ophaalwaarden kunnen ook een uitdrukking zijn die wordt geleverd als een variabele, parameter of constante scalaire subquery. Wanneer een subquery wordt gebruikt, kan deze niet verwijzen naar kolommen die zijn gedefinieerd in het buitenste querybereik (deze kan niet worden gecorreleerd met de buitenste query).
In de volgende voorbeelden worden expressies gebruikt om twee benaderingen te tonen voor het pagineren van de resultaten.
Voorbeeld 4 – Paginering op rijnummer
In dit voorbeeld worden expressies gebruikt om de rij . te specificeren nummer om mee te beginnen.
DECLARE @StartRow int = 1, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultaat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Hier gebruik ik @StartRow int = 1
om aan te geven dat de resultaten op de eerste rij moeten beginnen.
Dit is wat er gebeurt als ik die waarde verhoog naar 2
.
DECLARE @StartRow int = 2, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultaat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 2 | Jazz | | 3 | Country | | 4 | Pop | +-----------+---------+
Het begint op de tweede rij. Met deze methode kan ik de exacte rij specificeren om mee te beginnen.
Voorbeeld 5 – Paginering op paginanummer
Dit voorbeeld is bijna identiek aan het vorige voorbeeld, behalve dat u het paginanummer kunt specificeren, in plaats van het rijnummer.
DECLARE @PageNumber int = 1, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET (@PageNumber - 1) * @RowsPerPage ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultaat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Het eerste resultaat is dus hetzelfde. Laten we echter eens kijken wat er gebeurt als we @PageNumber
. verhogen tot 2
(Ik heb deze variabele hernoemd om het nieuwe doel weer te geven).
DECLARE @PageNumber int = 2, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET (@PageNumber - 1) * @RowsPerPage ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultaat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+
Deze keer beginnen de resultaten op de vierde rij. Met deze methode kunt u dus eenvoudig het paginanummer doorgeven in plaats van het rijnummer.
Voorbeeld 6 – Pagineringslus
Om af te ronden, hier is een snel voorbeeld dat door alle pagina's loopt en het startrijnummer voor elke iteratie specificeert:
DECLARE @StartRow int = 1, @RowsPerPage int = 3; WHILE (SELECT COUNT(*) FROM Genres) >= @StartRow BEGIN SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY; SET @StartRow = @StartRow + @RowsPerPage; CONTINUE END;
Resultaat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+ (3 rows affected) +-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+ (3 rows affected) +-----------+---------+ | GenreId | Genre | |-----------+---------| | 7 | Rap | | 8 | Punk | +-----------+---------+ (2 rows affected)
Voorbeeld 7 – RIJ versus RIJEN
Als u code tegenkomt die gebruikmaakt van ROW
in plaats van ROWS
, doen beide argumenten hetzelfde. Het zijn synoniemen en zijn bedoeld voor ANSI-compatibiliteit.
Hier is het eerste voorbeeld op deze pagina, maar met ROW
in plaats van ROWS
.
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH NEXT 3 ROW ONLY;
Resultaat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Voorbeeld 8 – EERSTE vs VOLGENDE
Hetzelfde geldt voor FIRST
en NEXT
. Dit zijn synoniemen voor ANSI-compatibiliteit.
Hier is het vorige voorbeeld, maar met FIRST
in plaats van NEXT
.
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH FIRST 3 ROW ONLY;
Resultaat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+