Oui. Avec une simple fonction fenêtre :
SELECT *, count(*) OVER() AS full_count
FROM tbl
WHERE /* whatever */
ORDER BY col1
OFFSET ?
LIMIT ?
Sachez que le coût sera nettement plus élevé que sans le nombre total, mais généralement moins cher que deux requêtes distinctes. Postgres doit en fait compter toutes les lignes dans les deux cas, ce qui impose un coût en fonction du nombre total de lignes éligibles. Détails :
- Meilleur moyen d'obtenir le nombre de résultats avant l'application de LIMIT
Cependant , comme l'a souligné Dani, lorsque OFFSET
est au moins aussi grand que le nombre de lignes renvoyées par la requête de base, aucune ligne n'est renvoyée. Donc, nous n'obtenons pas non plus full_count
.
Si cela n'est pas acceptable, une solution de contournement possible pour toujours renvoyer le nombre complet serait avec un CTE et un 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;
Vous obtenez une ligne de valeurs NULL avec le full_count
ajouté si OFFSET
C est trop gros. Sinon, il est ajouté à chaque ligne comme dans la première requête.
Si une ligne avec toutes les valeurs NULL est un résultat valide possible, vous devez vérifier offset >= full_count
pour désambiguïser l'origine de la ligne vide.
Cela exécute toujours la requête de base une seule fois. Mais cela ajoute plus de temps système à la requête et ne paie que si c'est moins que de répéter la requête de base pour le décompte.
Si des index prenant en charge l'ordre de tri final sont disponibles, il peut être avantageux d'inclure le ORDER BY
dans le CTE (en redondance).