Domanda

Dato che ho un tavolo con il seguente, contenuto molto semplice:

# select * from messages;
  id | verbosity 
 ----+-----------
   1 |        20
   2 |        20
   3 |        20
   4 |        30
   5 |       100
 (5 rows)
.

Vorrei selezionare n messaggi, quale somma della verbosità è inferiore a y (a scopo di test diciamo che dovrebbe essere 70, quindi i risultati corretti saranno messaggi con ID 1,2,3). È davvero importante per me, quella soluzione dovrebbe essere indipendente dal database (dovrebbe funzionare almeno su postgres e sqlite).

Stavo provando con qualcosa come:

SELECT * FROM messages GROUP BY id HAVING SUM(verbosity) < 70;
.

Tuttavia non sembra funzionare come previsto, perché in realtà non somma tutti i valori dalla colonna della verbosità.

Sarei molto grato per qualsiasi suggerimento / aiuto.

È stato utile?

Soluzione

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;
.

Questo presuppone un id unico ascendente come hai nel tuo esempio.


.

in Modern Postgres - o generalmente con Modern Standard SQL (ma non in SQLite):

semplice cte

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

ricorsivo cte

dovrebbe essere più veloce per le grandi tabelle in cui recupera 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 del LIMIT .

Sorveramente parlando, non esiste una cosa come "database-indipendente". Ci sono vari standard SQL, ma nessun RDBMS è conforme completamente. LIMIT funziona per PostgreSQL e SQLite (e alcuni altri). Utilizzare TOP 1 per SQL Server, rownum per Oracle. Ecco un lista completa su wikipedia.

SQL: 2008 Standard sarebbe:

...
FETCH  FIRST 1 ROWS ONLY
.

... quale postgresql supporta - ma a malapena qualsiasi altro RDBMS.

L'alternativa pura che funziona con più sistemi sarebbe di avvolgerla in una sottoquery e

SELECT max(total) FROM <subquery>
.

Ma questo è lento e ingombrante.

SQL Fiddle.

Altri suggerimenti

Questo funzionerà ...

select * 
from messages
where id<=
(
    select MAX(id) from
    (
        select m2.id, SUM(m1.verbosity) sv 
        from messages m1
        inner join messages m2 on m1.id <=m2.id
        group by m2.id
    ) v
    where sv<70
)
.

Tuttavia, è necessario comprendere che SQL è progettato come un linguaggio basato su set, anziché uno iterativo, quindi progettato per il trattamento dei dati come un set, piuttosto che su una riga per riga.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top