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