PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Elementos de seleção SQL em que a soma do campo é menor que 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;

Isso pressupõe um id exclusivo e crescente como você tem no seu exemplo.

No Postgres moderno - ou geralmente com SQL padrão moderno (mas não em SQLite):

CTE simples

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

CTE recursiva


Deve ser mais rápido para tabelas grandes, onde você recupera apenas um pequeno conjunto.
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;

Todos os recursos padrão, exceto LIMIT .

Estritamente falando, não existe algo como "independente do banco de dados". Existem vários padrões SQL, mas nenhum RDBMS cumpre completamente. LIMIT funciona para PostgreSQL e SQLite (e alguns outros). Use TOP 1 para SQL Server, rownum para Oráculo. Aqui está uma lista abrangente na Wikipedia.

O padrão SQL:2008 seria:
...
FETCH  FIRST 1 ROWS ONLY

... que o PostgreSQL suporta - mas quase nenhum outro RDBMS.

A alternativa pura que funciona com mais sistemas seria envolvê-lo em uma subconsulta e
SELECT max(total) FROM <subquery>

Mas isso é lento e pesado.

SQL Fiddle.