sql >> Databasteknik >  >> RDS >> Sqlserver

Paginering i SQL Server med OFFSET/FETCH

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

  1. Jämför DBaaS Failover-lösningar med manuella återställningsinställningar

  2. Topp fem mjukvaruapplikationer för åtkomst till MySQL/MariaDB-servrar

  3. pyodbc.connect() fungerar, men inte sqlalchemy.create_engine().connect()

  4. mysql SQL:specifik objekt ska vara först och sedan sortera resten av objekten