Sim. Com uma função de janela simples:
SELECT *, count(*) OVER() AS full_count
FROM tbl
WHERE
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 tem que contar todas as linhas de qualquer maneira, o que impõe um custo dependendo do número total de linhas qualificadas. Detalhes:
No entanto , como Dani apontou , quando OFFSET
é pelo menos tão grande quanto o número de linhas retornadas da consulta base, nenhuma linha é retornada. Então também não entendemos 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
)
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
for muito grande. Caso contrário, é anexado a todas as linhas, como na primeira consulta.
Se uma linha com todos os valores NULL for um resultado válido possível, você deve verificar offset >= full_count
para desambiguar a origem da linha vazia.
Isso ainda executa a consulta de base apenas uma vez. Mas adiciona mais sobrecarga à consulta e só paga se isso for menor do que repetir a consulta de 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).