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

Impaginazione in SQL Server tramite OFFSET/FETCH

L'impaginazione viene spesso utilizzata nelle applicazioni in cui l'utente può fare clic su Precedente /Avanti per navigare tra le pagine che compongono i risultati, oppure fare clic su un numero di pagina per andare direttamente a una pagina specifica.

Quando si eseguono query in SQL Server, è possibile impaginare i risultati utilizzando OFFSET e FETCH argomenti del ORDER BY clausola. Questi argomenti sono stati introdotti in SQL Server 2012, pertanto è possibile utilizzare questa tecnica se si dispone di SQL Server 2012 o versioni successive.

In questo contesto, l'impaginazione è il punto in cui dividi i risultati della query in blocchi più piccoli, ognuno dei quali continua da dove è terminato il precedente. Ad esempio, se una query restituisce 1000 righe, è possibile impaginarle in modo che vengano restituite in gruppi di 100. Un'applicazione può passare il numero di pagina e la dimensione della pagina a SQL Server e SQL Server può quindi utilizzarlo per restituire solo il dati per la pagina richiesta.

Esempio 1 – Nessuna impaginazione

Innanzitutto, eseguiamo una query che restituisce tutte le righe in una tabella:

SELECT *
FROM Genres
ORDER BY GenreId;

Risultato:

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

Questo esempio non utilizza l'impaginazione:vengono visualizzati tutti i risultati.

Questo set di risultati è così piccolo che normalmente non richiederebbe l'impaginazione, ma ai fini di questo articolo, impaginarlo.

Esempio 2 – Visualizza i primi 3 risultati

Questo esempio mostra i primi tre risultati:

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

Risultato:

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

In questo caso, specifico che i risultati devono iniziare dal primo risultato e visualizzare le tre righe successive. Questo viene fatto usando quanto segue:

  • OFFSET 0 ROWS specifica che non dovrebbe esserci alcun offset (un offset pari a zero).
  • FETCH NEXT 3 ROWS ONLY ottiene le tre righe successive dall'offset. Poiché ho specificato un offset pari a zero, vengono recuperate le prime tre righe.

Se tutto ciò che volevamo fossero i primi 3 risultati, avremmo potuto ottenere lo stesso risultato utilizzando il TOP clausola invece di specificare i valori di offset e fetch. Tuttavia, questo non ci avrebbe permesso di fare la parte successiva.

Esempio 3 – Visualizza i prossimi 3 risultati

Ora mostriamo i prossimi tre risultati:

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

Risultato:

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

Quindi l'unica cosa che ho cambiato è stato l'offset.

I valori di offset e recupero possono anche essere un'espressione fornita come sottoquery scalare variabile, parametro o costante. Quando viene utilizzata una sottoquery, non può fare riferimento a nessuna colonna definita nell'ambito della query esterna (non può essere correlata alla query esterna).

Gli esempi seguenti utilizzano espressioni per mostrare due approcci all'impaginazione dei risultati.

Esempio 4 – Impaginazione per numero di riga

Questo esempio usa espressioni per specificare la riga numero da cui iniziare.

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

Risultato:

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

Qui uso @StartRow int = 1 per specificare che i risultati devono iniziare dalla prima riga.

Ecco cosa succede se incremento quel valore a 2 .

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

Risultato:

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

Si comincia dalla seconda fila. Usando questo metodo, posso specificare la riga esatta da cui iniziare.

Esempio 5 – Impaginazione per numero di pagina

Questo esempio è quasi identico all'esempio precedente, tranne per il fatto che consente di specificare il numero di pagina, anziché il numero di riga.

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

Risultato:

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

Quindi il primo risultato è lo stesso. Tuttavia, vediamo cosa succede quando incrementiamo @PageNumber a 2 (Ho rinominato questa variabile per riflettere il suo nuovo scopo).

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

Risultato:

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

Questa volta i risultati iniziano dalla quarta fila. Quindi, usando questo metodo puoi semplicemente passare il numero di pagina anziché il numero di riga.

Esempio 6 – Ciclo di impaginazione

Per concludere, ecco un rapido esempio che scorre tutte le pagine e specifica il numero di riga iniziale per ogni iterazione:

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;

Risultato:

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

Esempio 7 – RIGA vs RIGA

Se incontri codice che utilizza ROW invece di ROWS , entrambi gli argomenti fanno la stessa cosa. Sono sinonimi e sono forniti per la compatibilità ANSI.

Ecco il primo esempio in questa pagina, ma con ROW invece di ROWS .

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

Risultato:

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

Esempio 8 – PRIMO vs PROSSIMO

Lo stesso vale per FIRST e NEXT . Questi sono sinonimi forniti per la compatibilità ANSI.

Ecco l'esempio precedente ma con FIRST invece di NEXT .

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

Risultato:

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