PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Execute uma consulta com um LIMIT/OFFSET e também obtenha o número total de linhas


Sim. Com uma função de janela simples:
SELECT *, count(*) OVER() AS full_count
FROM   tbl
WHERE  /* whatever */
ORDER  BY col1
OFFSET ?
LIMIT  ?

Esteja ciente de que o custo será substancialmente maior do que sem o número total, mas normalmente ainda mais barato do que duas consultas separadas. O Postgres precisa contar todas as linhas de qualquer maneira, o que impõe um custo dependendo do número total de linhas qualificadas. Detalhes:
  • Melhor maneira de obter a contagem de resultados antes da aplicação de LIMIT

No entanto , como Dani apontou, quando OFFSET for pelo menos tão grande quanto o número de linhas retornadas da consulta base, nenhuma linha será retornada. Portanto, também não recebemos full_count .

Se isso não for aceitável, uma possível solução alternativa para sempre retornar a contagem completa seria com um CTE e um OUTER JOIN :
WITH cte AS (
   SELECT *
   FROM   tbl
   WHERE  /* whatever */
   )
SELECT *
FROM  (
   TABLE  cte
   ORDER  BY col1
   LIMIT  ?
   OFFSET ?
   ) sub
RIGHT  JOIN (SELECT count(*) FROM cte) c(full_count) ON true;

Você obtém uma linha de valores NULL com o full_count anexado se OFFSET é muito grande. Caso contrário, é anexado a todas as linhas, como na primeira consulta.

Se uma linha com todos os valores NULL for um possível resultado válido, você deve verificar offset >= full_count para desambiguar a origem da linha vazia.

Isso ainda executa a consulta base apenas uma vez. Mas adiciona mais sobrecarga à consulta e só paga se for menos do que repetir a consulta base para a contagem.

Se os índices que suportam a ordem de classificação final estiverem disponíveis, pode valer a pena incluir o ORDER BY no CTE (redundantemente).