sql >> Database teknologi >  >> RDS >> Sqlserver

Sideinddeling i SQL Server ved hjælp af OFFSET/FETCH

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 |
+-----------+---------+

  1. Hvordan man kortlægger en streng til DB-sekvens i Hibernate

  2. SQL SELECT hastighed int vs varchar

  3. Transaktionsstyring med Django 1.6

  4. IS NOT NULL test for en post returnerer ikke TRUE, når variabel er indstillet