PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Exécutez une requête avec un LIMIT/OFFSET et obtenez également le nombre total de lignes

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