Sideinddeling bruges ofte i applikationer, hvor brugeren kan klikke på Forrige /Næste for at navigere på siderne, der udgør resultaterne, eller klik på et sidetal for at gå direkte til en bestemt side.
Når du kører forespørgsler i SQL Server, kan du paginere resultaterne ved at bruge OFFSET
og FETCH
argumenter for ORDER BY
klausul. Disse argumenter blev introduceret i SQL Server 2012, derfor kan du bruge denne teknik, hvis du har SQL Server 2012 eller højere.
I denne sammenhæng er paginering, hvor du opdeler forespørgselsresultaterne i mindre bidder, hvor hver chunk fortsætter, hvor den forrige sluttede. Hvis en forespørgsel f.eks. returnerer 1000 rækker, kan du paginere dem, så de returneres i grupper på 100. Et program kan videregive sidetallet og sidestørrelsen til SQL Server, og SQL Server kan derefter bruge det til at returnere data for den anmodede side.
Eksempel 1 – Ingen sideinddeling
Lad os først køre en forespørgsel, der returnerer alle rækker i en tabel:
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 | +-----------+---------+
Dette eksempel bruger ingen paginering – alle resultater vises.
Dette resultatsæt er så lille, at det normalt ikke ville kræve paginering, men i forbindelse med denne artikel, lad os paginere det.
Eksempel 2 – Vis de første 3 resultater
Dette eksempel viser de første tre resultater:
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
I dette tilfælde angiver jeg, at resultaterne skal starte ved det første resultat og vise de næste tre rækker. Dette gøres ved hjælp af følgende:
OFFSET 0 ROWS
angiver, at der ikke skal være nogen offset (en offset på nul).FETCH NEXT 3 ROWS ONLY
får de næste tre rækker fra offset. Da jeg har angivet en offset på nul, hentes de første tre rækker.
Hvis alt, hvad vi ønskede, var de 3 bedste resultater, kunne vi have opnået det samme resultat ved at bruge TOP
klausul i stedet for at specificere offset- og henteværdierne. Dette ville dog ikke have givet os mulighed for at gøre den næste del.
Eksempel 3 – Vis de næste 3 resultater
Lad os nu vise de næste tre resultater:
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 eneste, jeg ændrede, var forskydningen.
Værdierne for forskydning og hentning kan også være et udtryk, der leveres som en variabel, parameter eller konstant skalær underforespørgsel. Når en underforespørgsel bruges, kan den ikke referere til nogen kolonner, der er defineret i det ydre forespørgselsomfang (det kan ikke korreleres med den ydre forespørgsel).
De følgende eksempler bruger udtryk til at vise to tilgange til paginering af resultaterne.
Eksempel 4 – Sideinddeling efter rækkenummer
Dette eksempel bruger udtryk til at specificere rækken nummer at starte ved.
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 | +-----------+---------+
Her bruger jeg @StartRow int = 1
for at angive, at resultaterne skal starte i første række.
Her er, hvad der sker, hvis jeg øger denne værdi til 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 starter på anden række. Ved at bruge denne metode kan jeg angive den nøjagtige række, der skal startes ved.
Eksempel 5 – Sideinddeling efter sidenummer
Dette eksempel er næsten identisk med det foregående eksempel, bortset fra at det giver dig mulighed for at angive sidenummeret i modsætning til rækkenummeret.
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ørste resultat er det samme. Lad os dog se, hvad der sker, når vi øger @PageNumber
til 2
(Jeg omdøbte denne variabel for at afspejle dens nye formål).
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 | +-----------+---------+
Denne gang starter resultaterne på fjerde række. Så ved at bruge denne metode kan du blot sende sidenummeret i stedet for rækkenummeret.
Eksempel 6 – Pagineringsløkke
For at afslutte, er her et hurtigt eksempel, der går gennem alle sider og specificerer startrækkenummeret for hver 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)
Eksempel 7 – RÆKKER vs RÆKKER
Hvis du støder på kode, der bruger ROW
i stedet for ROWS
, begge argumenter gør det samme. De er synonymer og leveres til ANSI-kompatibilitet.
Her er det første eksempel på denne side, men med ROW
i stedet for ROWS
.
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH NEXT 3 ROW ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Eksempel 8 – FØRST vs NÆSTE
Det samme gælder for FIRST
og NEXT
. Disse er synonymer til ANSI-kompatibilitet.
Her er det forrige eksempel, men med FIRST
i stedet for NEXT
.
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH FIRST 3 ROW ONLY;
Resultat:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+