Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Paginierung in SQL Server mit OFFSET/FETCH

Paginierung wird häufig in Anwendungen verwendet, in denen der Benutzer auf Zurück klicken kann /Weiter um durch die Seiten zu navigieren, aus denen sich die Ergebnisse zusammensetzen, oder klicken Sie auf eine Seitennummer, um direkt zu einer bestimmten Seite zu gelangen.

Beim Ausführen von Abfragen in SQL Server können Sie die Ergebnisse paginieren, indem Sie OFFSET verwenden und FETCH Argumente von ORDER BY Klausel. Diese Argumente wurden in SQL Server 2012 eingeführt, daher können Sie diese Technik verwenden, wenn Sie über SQL Server 2012 oder höher verfügen.

In diesem Zusammenhang teilen Sie bei der Paginierung die Abfrageergebnisse in kleinere Abschnitte auf, wobei jeder Abschnitt dort fortgesetzt wird, wo der vorherige aufgehört hat. Wenn eine Abfrage beispielsweise 1000 Zeilen zurückgibt, können Sie sie so paginieren, dass sie in Gruppen von 100 zurückgegeben werden. Eine Anwendung kann die Seitennummer und die Seitengröße an SQL Server übergeben, und SQL Server kann sie dann verwenden, um nur die zurückzugeben Daten für die angeforderte Seite.

Beispiel 1 – Keine Paginierung

Lassen Sie uns zuerst eine Abfrage ausführen, die alle Zeilen in einer Tabelle zurückgibt:

SELECT *
FROM Genres
ORDER BY GenreId;

Ergebnis:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
| 4         | Pop     |
| 5         | Blues   |
| 6         | Hip Hop |
| 7         | Rap     |
| 8         | Punk    |
+-----------+---------+

Dieses Beispiel verwendet keine Paginierung – alle Ergebnisse werden angezeigt.

Diese Ergebnismenge ist so klein, dass normalerweise keine Paginierung erforderlich wäre, aber für die Zwecke dieses Artikels sollten wir sie paginieren.

Beispiel 2 – Anzeige der ersten 3 Ergebnisse

Dieses Beispiel zeigt die ersten drei Ergebnisse:

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 0 ROWS
  FETCH NEXT 3 ROWS ONLY;

Ergebnis:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

In diesem Fall gebe ich an, dass die Ergebnisse beim ersten Ergebnis beginnen und die nächsten drei Zeilen anzeigen sollen. Dies geschieht wie folgt:

  • OFFSET 0 ROWS gibt an, dass es keinen Offset geben soll (ein Offset von Null).
  • FETCH NEXT 3 ROWS ONLY erhält die nächsten drei Zeilen vom Offset. Da ich einen Offset von Null angegeben habe, werden die ersten drei Zeilen abgerufen.

Wenn wir nur die Top-3-Ergebnisse wollten, hätten wir dasselbe Ergebnis mit TOP erzielen können -Klausel, anstatt die Offset- und Abrufwerte anzugeben. Dies hätte uns jedoch nicht erlaubt, den nächsten Teil zu machen.

Beispiel 3 – Anzeige der nächsten 3 Ergebnisse

Lassen Sie uns nun die nächsten drei Ergebnisse anzeigen:

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 3 ROWS
  FETCH NEXT 3 ROWS ONLY;

Ergebnis:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 4         | Pop     |
| 5         | Blues   |
| 6         | Hip Hop |
+-----------+---------+

Das einzige, was ich geändert habe, war der Offset.

Die Offset- und Abrufwerte können auch ein Ausdruck sein, der als Variable, Parameter oder konstante skalare Unterabfrage bereitgestellt wird. Wenn eine Unterabfrage verwendet wird, kann sie nicht auf Spalten verweisen, die im äußeren Abfragebereich definiert sind (sie kann nicht mit der äußeren Abfrage korreliert werden).

Die folgenden Beispiele verwenden Ausdrücke, um zwei Ansätze zum Paginieren der Ergebnisse zu zeigen.

Beispiel 4 – Paginierung nach Zeilennummer

Dieses Beispiel verwendet Ausdrücke, um die Zeile anzugeben Startnummer.

DECLARE 
  @StartRow int = 1,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET @StartRow - 1 ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Ergebnis:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

Hier verwende ich @StartRow int = 1 um anzugeben, dass die Ergebnisse in der ersten Zeile beginnen sollen.

Folgendes passiert, wenn ich diesen Wert auf 2 erhöhe .

DECLARE 
  @StartRow int = 2,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET @StartRow - 1 ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Ergebnis:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 2         | Jazz    |
| 3         | Country |
| 4         | Pop     |
+-----------+---------+

Es beginnt in der zweiten Reihe. Mit dieser Methode kann ich die genaue Zeile angeben, bei der ich beginnen soll.

Beispiel 5 – Paginierung nach Seitenzahl

Dieses Beispiel ist fast identisch mit dem vorherigen Beispiel, mit der Ausnahme, dass Sie die Seitennummer anstelle der Zeilennummer angeben können.

DECLARE 
  @PageNumber int = 1,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET (@PageNumber - 1) * @RowsPerPage ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Ergebnis:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

Das erste Ergebnis ist also dasselbe. Sehen wir uns jedoch an, was passiert, wenn wir @PageNumber erhöhen zu 2 (Ich habe diese Variable umbenannt, um ihren neuen Zweck widerzuspiegeln).

DECLARE 
  @PageNumber int = 2,
  @RowsPerPage int = 3;
  
SELECT *  
FROM Genres
ORDER BY GenreId ASC
    OFFSET (@PageNumber - 1) * @RowsPerPage ROWS
    FETCH NEXT @RowsPerPage ROWS ONLY;

Ergebnis:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 4         | Pop     |
| 5         | Blues   |
| 6         | Hip Hop |
+-----------+---------+

Diesmal beginnen die Ergebnisse in der vierten Reihe. Mit dieser Methode können Sie also einfach die Seitennummer statt der Zeilennummer übergeben.

Beispiel 6 – Paginierungsschleife

Zum Abschluss ist hier ein kurzes Beispiel, das alle Seiten durchläuft und die Anfangszeilennummer für jede Iteration angibt:

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;

Ergebnis:

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

Beispiel 7 – REIHE vs. REIHE

Wenn Sie auf Code stoßen, der ROW verwendet statt ROWS , machen beide Argumente dasselbe. Sie sind Synonyme und dienen der ANSI-Kompatibilität.

Hier ist das erste Beispiel auf dieser Seite, aber mit ROW statt ROWS .

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 0 ROW
  FETCH NEXT 3 ROW ONLY;

Ergebnis:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+

Beispiel 8 – ERSTER vs. NÄCHSTER

Gleiches gilt für FIRST und NEXT . Dies sind Synonyme für die ANSI-Kompatibilität.

Hier ist das vorherige Beispiel, aber mit FIRST statt NEXT .

SELECT *
FROM Genres
ORDER BY GenreId
  OFFSET 0 ROW
  FETCH FIRST 3 ROW ONLY;

Ergebnis:

+-----------+---------+
| GenreId   | Genre   |
|-----------+---------|
| 1         | Rock    |
| 2         | Jazz    |
| 3         | Country |
+-----------+---------+