PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

SQL sélectionne les éléments où la somme des champs est inférieure à 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;

Cela suppose un id unique et croissant comme vous l'avez dans votre exemple.

Dans Postgres moderne - ou généralement avec SQL standard moderne (mais pas en SQLite) :

CTE simple

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

CTE récursif

Devrait être plus rapide pour les grandes tables où vous ne récupérez qu'un petit ensemble.

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;

Toutes les fonctionnalités standard, à l'exception de LIMIT .

Strictement parlant, il n'existe pas de "base de données indépendante". Il existe différentes normes SQL, mais aucun SGBDR ne s'y conforme complètement. LIMIT fonctionne pour PostgreSQL et SQLite (et quelques autres). Utilisez TOP 1 pour SQL Server, rownum pour Oracle. Voici une liste complète sur Wikipédia.

La norme SQL:2008 serait :

...
FETCH  FIRST 1 ROWS ONLY

... que PostgreSQL prend en charge - mais pratiquement aucun autre SGBDR.

L'alternative pure qui fonctionne avec plus de systèmes serait de l'envelopper dans une sous-requête et

SELECT max(total) FROM <subquery>

Mais c'est lent et peu maniable.

SQL Fiddle.