sql >> Databáze >  >> RDS >> PostgreSQL

SQL select elementy, kde součet polí je menší než 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;

To předpokládá jedinečné, vzestupné id jako máte ve svém příkladu.

V moderním Postgresu – nebo obecně s moderním standardním SQL (ale ne v SQLite):

Jednoduché CTE

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

Rekurzivní CTE

Mělo by být rychlejší pro velké stoly, kde získáváte pouze malou sadu.

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;

Všechny standardní funkce kromě LIMIT .

Přísně vzato, neexistuje nic jako „nezávislý na databázi“. Existují různé standardy SQL, ale žádný RDBMS zcela nevyhovuje. LIMIT funguje pro PostgreSQL a SQLite (a některé další). Použijte TOP 1 pro SQL Server rownum pro Oracle. Zde je úplný seznam na Wikipedii.

Standard SQL:2008 by byl:

...
FETCH  FIRST 1 ROWS ONLY

...které PostgreSQL podporuje - ale téměř žádné jiné RDBMS.

Čistá alternativa, která funguje s více systémy, by bylo zabalit to do poddotazu a

SELECT max(total) FROM <subquery>

Ale to je pomalé a nepraktické.

SQL Fiddle.



  1. Příklady MySQL SOUNDEX().

  2. Funkce PL/pgSQL:Jak vrátit normální tabulku s více sloupci pomocí příkazu execute

  3. 15 užitečných tipů pro ladění a optimalizaci výkonu MySQL/MariaDB

  4. Rozdíl mezi LIKE a ~ v Postgresu