Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Paginação no SQL Server usando OFFSET/FETCH


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