sql >> Database teknologi >  >> RDS >> PostgreSQL

Kør en forespørgsel med en LIMIT/OFFSET og få også det samlede antal rækker

Ja. Med en simpel vinduesfunktion:

SELECT *, count(*) OVER() AS full_count
FROM   tbl
WHERE  /* whatever */
ORDER  BY col1
OFFSET ?
LIMIT  ?

Vær opmærksom på, at prisen vil være væsentligt højere end uden det samlede antal, men typisk stadig billigere end to separate forespørgsler. Postgres skal faktisk tælle alle rækker begge veje, hvilket pålægger en omkostning afhængig af det samlede antal kvalificerende rækker. Detaljer:

  • Bedste måde at få resultattælling, før LIMIT blev anvendt

Men , som Dani påpegede, da OFFSET er mindst lige så stort som antallet af rækker, der returneres fra basisforespørgslen, returneres ingen rækker. Så vi får heller ikke full_count .

Hvis det ikke er acceptabelt, er en mulig løsning for altid at returnere det fulde antal ville være med en CTE og en 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;

Du får en række NULL-værdier med full_count tilføjet hvis OFFSET er for stor. Ellers er den tilføjet til hver række som i den første forespørgsel.

Hvis en række med alle NULL-værdier er et muligt gyldigt resultat, skal du kontrollere offset >= full_count for at tvetydige oprindelsen af ​​den tomme række.

Dette udfører stadig kun basisforespørgslen én gang. Men det føjer mere overhead til forespørgslen og betaler kun, hvis det er mindre end at gentage basisforespørgslen for optællingen.

Hvis indekser, der understøtter den endelige sorteringsrækkefølge, er tilgængelige, kan det betale sig at inkludere ORDER BY i CTE (redundant).



  1. OPENROWSET accepterer ikke variabler for sine argumenter (SQL-server)

  2. Postgresql indsæt trigger for at indstille værdi

  3. Sender tabelnavn som en parameter i psycopg2

  4. Baggrundsprocesser