(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Como paginar resultados no SQL Server com OFFSET FETCH

João Barros 05 de July de 2026 4 min de leitura

Quando uma consulta no SQL Server devolve milhares de linhas, mostrar tudo de uma vez é impraticável: o melhor é dividir os dados em páginas. A forma mais simples e legível de paginar resultados no SQL Server é a cláusula OFFSET FETCH, disponível desde o SQL Server 2012 e também no Azure SQL Database. A seguir tens um exemplo prático, passo a passo, e o erro mais comum a evitar. O OFFSET indica quantas linhas saltar e o FETCH quantas devolver a seguir.

Pré-requisitos

  • Uma instância de SQL Server 2012 ou superior (também funciona no Azure SQL Database).
  • O SQL Server Management Studio (SSMS) ou o Azure Data Studio para correr as consultas.
  • Uma tabela com vários registos para testar — no exemplo usamos dbo.Encomendas.
  • Noções básicas de SELECT e ORDER BY.

Passo 1: Perceber porque o ORDER BY é obrigatório

A cláusula OFFSET FETCH funciona em dois tempos: primeiro "salta" um número de linhas e depois "traz" as linhas seguintes. Para que saltar e trazer tenham significado, o SQL Server precisa de uma ordem bem definida — por isso o OFFSET só pode aparecer a seguir a um ORDER BY. Sem ordenação, o motor não garante qual a linha que vem primeiro e a paginação ficaria imprevisível.

Erro comum: escrever OFFSET sem ORDER BY. Nesse caso o SQL Server devolve um erro de sintaxe, porque o OFFSET faz parte da própria cláusula ORDER BY. Ordena sempre antes de saltar linhas.

Passo 2: Conhecer a sintaxe OFFSET FETCH

A estrutura é sempre a mesma: ordenas, saltas com OFFSET e trazes um bloco com FETCH NEXT. Este exemplo devolve as 10 encomendas mais recentes:

SELECT EncomendaID, Cliente, DataEncomenda, Total
FROM dbo.Encomendas
ORDER BY DataEncomenda DESC, EncomendaID DESC
OFFSET 0 ROWS
FETCH NEXT 10 ROWS ONLY;

OFFSET 0 ROWS quer dizer "não saltes nenhuma linha" e FETCH NEXT 10 ROWS ONLY quer dizer "traz apenas as 10 seguintes". As palavras ROWS/ROW e NEXT/FIRST são sinónimos — escolhe as que tornarem a consulta mais legível.

Passo 3: Calcular a página com uma fórmula simples

Para saltar para qualquer página só precisas de dois valores: o número da página e o tamanho da página. O número de linhas a saltar é (página - 1) * tamanho. Este exemplo mostra a página 3, com 10 registos por página, ou seja, salta as primeiras 20 linhas:

DECLARE @Pagina  INT = 3;
DECLARE @Tamanho INT = 10;

SELECT EncomendaID, Cliente, DataEncomenda, Total
FROM dbo.Encomendas
ORDER BY DataEncomenda DESC, EncomendaID DESC
OFFSET (@Pagina - 1) * @Tamanho ROWS
FETCH NEXT @Tamanho ROWS ONLY;

Mudando apenas o valor de @Pagina para 1, 2, 3… percorres todos os resultados, bloco a bloco. É exatamente este o padrão que corre por trás de uma tabela com botões "Anterior" e "Seguinte" ou de uma API que devolve dados paginados. Mantém o @Tamanho igual em todas as páginas para que a navegação seja consistente.

Passo 4: Ordenar por uma coluna única para paginação estável

Se ordenares apenas por uma coluna com valores repetidos (por exemplo, só por DataEncomenda), duas encomendas com a mesma data podem trocar de posição entre execuções e acabar na página errada — ou aparecer duas vezes. A solução é acrescentar sempre uma coluna única como critério de desempate, normalmente a chave primária:

ORDER BY DataEncomenda DESC, EncomendaID DESC

Com um desempate único, a ordem passa a ser determinística e cada linha aparece exatamente numa página.

Verificar o resultado

Corre a consulta com @Pagina = 1 e depois com @Pagina = 2: cada uma deve devolver 10 linhas e não pode existir nenhum registo repetido entre as duas páginas. Para saber quantas páginas existem no total, divide o número de linhas pelo tamanho da página e arredonda para cima:

DECLARE @Tamanho INT = 10;

SELECT CEILING(COUNT(*) * 1.0 / @Tamanho) AS TotalPaginas
FROM dbo.Encomendas;

Se a última página trouxer menos de 10 linhas, está tudo certo: é apenas o resto dos registos.

Conclusão

Com ORDER BY mais OFFSET FETCH tens uma paginação legível, padronizada e fácil de manter, ideal para alimentar tabelas na interface e APIs. Para páginas muito profundas — quando saltas dezenas de milhares de linhas — o OFFSET pode tornar-se lento; nesse cenário vale a pena estudar a keyset pagination, que pagina a partir da última chave lida. Esta abordagem faz parte do padrão ANSI SQL, por isso o mesmo raciocínio aplica-se a outros motores como o PostgreSQL. Um bom próximo passo é criar um índice pelas colunas do teu ORDER BY e comparar o tempo de resposta. Qual das tuas consultas mais pesadas ias paginar primeiro?