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

Esegui una query con un LIMIT/OFFSET e ottieni anche il numero totale di righe

Sì. Con una semplice funzione finestra:

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

Tieni presente che il costo sarà sostanzialmente superiore rispetto a quello senza il numero totale, ma in genere sarà comunque più economico di due query separate. Postgres deve effettivamente contare tutte le righe in entrambi i casi, il che impone un costo che dipende dal numero totale di righe qualificanti. Dettagli:

  • Il modo migliore per ottenere il conteggio dei risultati prima dell'applicazione del LIMIT

Tuttavia , come ha sottolineato Dani, quando OFFSET è almeno pari al numero di righe restituite dalla query di base, non vengono restituite righe. Quindi non otteniamo nemmeno full_count .

Se ciò non è accettabile, una possibile soluzione alternativa per restituire sempre il conteggio completo sarebbe con un CTE e 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;

Ottieni una riga di valori NULL con full_count aggiunto se OFFSET è troppo grande. Altrimenti, viene aggiunto a ogni riga come nella prima query.

Se una riga con tutti i valori NULL è un possibile risultato valido devi controllare offset >= full_count per chiarire l'origine della riga vuota.

Questo esegue ancora la query di base solo una volta. Ma aggiunge più sovraccarico alla query e paga solo se è inferiore alla ripetizione della query di base per il conteggio.

Se sono disponibili indici che supportano l'ordinamento finale, potrebbe essere utile includere ORDER BY nel CTE (ridondante).