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

SQL seleziona elementi in cui la somma del campo è inferiore a N

SELECT m.id, sum(m1.verbosity) AS total
FROM   messages m
JOIN   messages m1 ON m1.id <= m.id
WHERE  m.verbosity < 70    -- optional, to avoid pointless evaluation
GROUP  BY m.id
HAVING SUM(m1.verbosity) < 70
ORDER  BY total DESC
LIMIT  1;

Ciò presuppone un id univoco crescente come hai nel tuo esempio.

Nel moderno Postgres - o in generale con SQL standard moderno (ma non in SQLite):

CTE semplice

WITH cte AS (
   SELECT *, sum(verbosity) OVER (ORDER BY id) AS total
   FROM   messages
   )
SELECT *
FROM   cte
WHERE  total <= 70
ORDER  BY id;

CTE ricorsivo

Dovrebbe essere più veloce per i tavoli grandi in cui recuperi solo un piccolo set.

WITH RECURSIVE cte AS (
   (  -- parentheses required
   SELECT id, verbosity, verbosity AS total
   FROM   messages
   ORDER  BY id
   LIMIT  1
   )

   UNION ALL 
   SELECT c1.id, c1.verbosity, c.total + c1.verbosity 
   FROM   cte c
   JOIN   LATERAL (
      SELECT *
      FROM   messages
      WHERE  id > c.id
      ORDER  BY id
      LIMIT  1
      ) c1 ON  c1.verbosity <= 70 - c.total
   WHERE c.total <= 70
   )
SELECT *
FROM   cte
ORDER  BY id;

Tutte le funzionalità standard, ad eccezione di LIMIT .

A rigor di termini, non esiste una cosa come "indipendente dal database". Esistono vari standard SQL, ma nessun RDBMS è completamente conforme. LIMIT funziona per PostgreSQL e SQLite (e alcuni altri). Usa TOP 1 per SQL Server, rownum per Oracle. Ecco un elenco completo su Wikipedia.

Lo standard SQL:2008 sarebbe:

...
FETCH  FIRST 1 ROWS ONLY

... che supporta PostgreSQL, ma quasi nessun altro RDBMS.

La pura alternativa che funziona con più sistemi sarebbe quella di avvolgerlo in una sottoquery e

SELECT max(total) FROM <subquery>

Ma è lento e ingombrante.

SQL Fiddle.