sql >> Databasteknik >  >> RDS >> PostgreSQL

Kör en fråga med en LIMIT/OFFSET och få även det totala antalet rader

Ja. Med en enkel fönsterfunktion:

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

Tänk på att kostnaden kommer att vara betydligt högre än utan det totala antalet, men vanligtvis fortfarande billigare än två separata frågor. Postgres måste faktiskt räkna alla rader i båda fallen, vilket medför en kostnad beroende på det totala antalet kvalificerade rader. Detaljer:

  • Bästa sättet att få resultaträkningen innan LIMIT tillämpades

Men , som Dani påpekade, när OFFSET är minst lika stort som antalet rader som returneras från basfrågan, returneras inga rader. Så vi får inte heller full_count .

Om det inte är acceptabelt, en möjlig lösning för att alltid returnera hela antalet skulle vara med en CTE och 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 rad med NULL-värden med full_count läggs till om OFFSET är för stor. Annars läggs den till på varje rad som i den första frågan.

Om en rad med alla NULL-värden är ett möjligt giltigt resultat måste du kontrollera offset >= full_count för att disambiguera ursprunget för den tomma raden.

Detta kör fortfarande basfrågan bara en gång. Men det lägger till mer overhead till frågan och betalar bara om det är mindre än att upprepa basfrågan för räkningen.

Om index som stöder den slutliga sorteringsordningen är tillgängliga kan det löna sig att inkludera ORDER BY i CTE (redundant).



  1. ORA-16205 Uppgradering till 11.2.0.3

  2. Hur använder man bilder i Android SQLite som är större än begränsningarna för ett CursorWindow?

  3. Flera sätt att infoga delade avgränsade strängar i en kolumn

  4. T-SQL datumtid avrundad till närmaste minut och närmaste timmar med hjälp av funktioner