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).