Paginering används ofta i applikationer där användaren kan klicka på Föregående /Nästa för att navigera på sidorna som utgör resultaten, eller klicka på ett sidnummer för att gå direkt till en specifik sida.
När du kör frågor i SQL Server kan du paginera resultaten genom att använda OFFSET
och FETCH
argument för ORDER BY
klausul. Dessa argument introducerades i SQL Server 2012, därför kan du använda den här tekniken om du har SQL Server 2012 eller högre.
I detta sammanhang är paginering där du delar upp frågeresultaten i mindre bitar, där varje bit fortsätter där den föregående slutade. Till exempel, om en fråga returnerar 1000 rader kan du sidnumrera dem så att de returneras i grupper om 100. En applikation kan skicka sidnumret och sidstorleken till SQL Server, och SQL Server kan sedan använda det för att returnera bara data för den begärda sidan.
Exempel 1 – Ingen paginering
Låt oss först köra en fråga som returnerar alla rader i en tabell:
SELECT * FROM Genres ORDER BY GenreId;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | | 7 | Rap | | 8 | Punk | +-----------+---------+
Det här exemplet använder ingen sidnumrering – alla resultat visas.
Den här resultatuppsättningen är så liten att den normalt inte skulle kräva sidnumrering, men för den här artikelns syften, låt oss paginera den.
Exempel 2 – Visa de tre första resultaten
Det här exemplet visar de tre första resultaten:
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
I det här fallet anger jag att resultaten ska börja vid det första resultatet och visa de tre följande raderna. Detta görs med följande:
OFFSET 0 ROWS
anger att det inte ska finnas någon offset (en offset på noll).FETCH NEXT 3 ROWS ONLY
får nästa tre rader från offset. Eftersom jag angav en offset på noll, hämtas de tre första raderna.
Om allt vi ville ha var de tre bästa resultaten, kunde vi ha uppnått samma resultat genom att använda TOP
i stället för att specificera offset- och hämtningsvärdena. Detta skulle dock inte ha tillåtit oss att göra nästa del.
Exempel 3 – Visa nästa 3 resultat
Låt oss nu visa nästa tre resultat:
SELECT * FROM Genres ORDER BY GenreId OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+
Så det enda jag ändrade var offset.
Offset- och hämtningsvärdena kan också vara ett uttryck som tillhandahålls som en variabel, parameter eller konstant skalär underfråga. När en underfråga används kan den inte referera till några kolumner definierade i det yttre frågeomfånget (det kan inte korreleras med den yttre frågan).
Följande exempel använder uttryck för att visa två metoder för sidnumrering av resultaten.
Exempel 4 – Paginering efter radnummer
Det här exemplet använder uttryck för att specificera raden nummer att börja på.
DECLARE @StartRow int = 1, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Här använder jag @StartRow int = 1
för att ange att resultaten ska börja på första raden.
Här är vad som händer om jag ökar det värdet till 2
.
DECLARE @StartRow int = 2, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 2 | Jazz | | 3 | Country | | 4 | Pop | +-----------+---------+
Det börjar på andra raden. Med den här metoden kan jag ange den exakta raden som ska börja på.
Exempel 5 – Paginering efter sidnummer
Det här exemplet är nästan identiskt med det föregående exemplet, förutom att det låter dig ange sidnumret, i motsats till radnumret.
DECLARE @PageNumber int = 1, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET (@PageNumber - 1) * @RowsPerPage ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Så det första resultatet är detsamma. Men låt oss se vad som händer när vi ökar @PageNumber
till 2
(Jag döpte om den här variabeln för att återspegla dess nya syfte).
DECLARE @PageNumber int = 2, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET (@PageNumber - 1) * @RowsPerPage ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+
Den här gången börjar resultaten på fjärde raden. Så med den här metoden kan du helt enkelt skicka sidnumret istället för radnumret.
Exempel 6 – Pagineringsslinga
För att avsluta, här är ett snabbt exempel som går igenom alla sidor och anger startradens nummer för varje iteration:
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;
Resultat:
+-----------+---------+ | 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)
Exempel 7 – ROW vs ROWS
Om du stöter på kod som använder ROW
istället för ROWS
, båda argumenten gör samma sak. De är synonymer och tillhandahålls för ANSI-kompatibilitet.
Här är det första exemplet på den här sidan, men med ROW
istället för ROWS
.
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH NEXT 3 ROW ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Exempel 8 – FÖRSTA vs NÄSTA
Detsamma gäller för FIRST
och NEXT
. Dessa är synonymer som tillhandahålls för ANSI-kompatibilitet.
Här är det tidigare exemplet men med FIRST
istället för NEXT
.
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH FIRST 3 ROW ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+