A paginação é frequentemente usada em aplicativos onde o usuário pode clicar em Anterior /Próximo para navegar pelas páginas que compõem os resultados, ou clique em um número de página para ir diretamente a uma página específica.
Ao executar consultas no SQL Server, você pode paginar os resultados usando o
OFFSET
e FETCH
argumentos do ORDER BY
cláusula. Esses argumentos foram introduzidos no SQL Server 2012, portanto, você pode usar essa técnica se tiver o SQL Server 2012 ou superior. Nesse contexto, a paginação é onde você divide os resultados da consulta em partes menores, cada parte continuando onde a anterior terminou. Por exemplo, se uma consulta retornar 1.000 linhas, você poderá paginá-las para que sejam retornadas em grupos de 100. Um aplicativo pode passar o número da página e o tamanho da página para o SQL Server, e o SQL Server pode usá-lo para retornar apenas o dados para a página solicitada.
Exemplo 1 – Sem paginação
Primeiro, vamos executar uma consulta que retorna todas as linhas de uma tabela:
SELECT * FROM Genres ORDER BY GenreId;
Resultado:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | | 7 | Rap | | 8 | Punk | +-----------+---------+
Este exemplo não usa paginação – todos os resultados são exibidos.
Esse conjunto de resultados é tão pequeno que normalmente não exigiria paginação, mas para os propósitos deste artigo, vamos paginar.
Exemplo 2 – Exibir os 3 primeiros resultados
Este exemplo exibe os três primeiros resultados:
SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;
Resultado:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Nesse caso, especifico que os resultados devem começar no primeiro resultado e exibir as próximas três linhas. Isso é feito usando o seguinte:
OFFSET 0 ROWS
especifica que não deve haver deslocamento (um deslocamento de zero).FETCH NEXT 3 ROWS ONLY
obtém as próximas três linhas do deslocamento. Como especifiquei um deslocamento de zero, as três primeiras linhas são buscadas.
Se tudo o que queríamos fossem os 3 principais resultados, poderíamos ter alcançado o mesmo resultado usando o
TOP
cláusula em vez de especificar os valores de deslocamento e busca. No entanto, isso não nos permitiria fazer a próxima parte. Exemplo 3 – Exibir os próximos 3 resultados
Agora vamos exibir os próximos três resultados:
SELECT * FROM Genres ORDER BY GenreId OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY;
Resultado:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+
Então a única coisa que eu mudei foi o offset.
Os valores de deslocamento e busca também podem ser uma expressão fornecida como uma variável, parâmetro ou subconsulta escalar constante. Quando uma subconsulta é usada, ela não pode fazer referência a nenhuma coluna definida no escopo da consulta externa (não pode ser correlacionada com a consulta externa).
Os exemplos a seguir usam expressões para mostrar duas abordagens para paginar os resultados.
Exemplo 4 – Paginação por Número de Linha
Este exemplo usa expressões para especificar a linha número para começar.
DECLARE @StartRow int = 1, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultado:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Aqui, eu uso
@StartRow int = 1
para especificar que os resultados devem começar na primeira linha. Aqui está o que acontece se eu incrementar esse valor para
2
. DECLARE @StartRow int = 2, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET @StartRow - 1 ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultado:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 2 | Jazz | | 3 | Country | | 4 | Pop | +-----------+---------+
Ele começa na segunda linha. Usando esse método, posso especificar a linha exata para começar.
Exemplo 5 – Paginação por Número de Página
Este exemplo é quase idêntico ao exemplo anterior, exceto que permite especificar o número da página, em oposição ao número da linha.
DECLARE @PageNumber int = 1, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET (@PageNumber - 1) * @RowsPerPage ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultado:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Então o primeiro resultado é o mesmo. No entanto, vamos ver o que acontece quando incrementamos
@PageNumber
para 2
(Renomeei esta variável para refletir seu novo propósito). DECLARE @PageNumber int = 2, @RowsPerPage int = 3; SELECT * FROM Genres ORDER BY GenreId ASC OFFSET (@PageNumber - 1) * @RowsPerPage ROWS FETCH NEXT @RowsPerPage ROWS ONLY;
Resultado:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 4 | Pop | | 5 | Blues | | 6 | Hip Hop | +-----------+---------+
Desta vez, os resultados começam na quarta linha. Portanto, usando esse método, você pode simplesmente passar o número da página em vez do número da linha.
Exemplo 6 – Loop de paginação
Para finalizar, aqui está um exemplo rápido que percorre todas as páginas e especifica o número da linha inicial para cada iteração:
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;
Resultado:
+-----------+---------+ | 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)
Exemplo 7 – LINHAS vs LINHAS
Se você encontrar um código que use
ROW
em vez de ROWS
, ambos os argumentos fazem a mesma coisa. Eles são sinônimos e são fornecidos para compatibilidade com ANSI. Aqui está o primeiro exemplo nesta página, mas com
ROW
em vez de ROWS
. SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH NEXT 3 ROW ONLY;
Resultado:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+
Exemplo 8 – PRIMEIRO x PRÓXIMO
O mesmo se aplica a
FIRST
e NEXT
. Estes são sinônimos fornecidos para compatibilidade ANSI. Aqui está o exemplo anterior, mas com
FIRST
em vez de NEXT
. SELECT * FROM Genres ORDER BY GenreId OFFSET 0 ROW FETCH FIRST 3 ROW ONLY;
Resultado:
+-----------+---------+ | GenreId | Genre | |-----------+---------| | 1 | Rock | | 2 | Jazz | | 3 | Country | +-----------+---------+