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;
Zakłada to unikalny, rosnąco id
jak masz w swoim przykładzie.
We współczesnym Postgresie – lub ogólnie w nowoczesnym standardowym SQL (ale nie w SQLite):
Proste CTE
WITH cte AS (
SELECT *, sum(verbosity) OVER (ORDER BY id) AS total
FROM messages
)
SELECT *
FROM cte
WHERE total <= 70
ORDER BY id;
Rekursywne CTE
Powinno być szybsze w przypadku dużych stołów, gdzie pobierasz tylko mały zestaw.
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;
Wszystkie standardowe funkcje, z wyjątkiem LIMIT
.
Ściśle mówiąc, nie ma czegoś takiego jak „niezależność od bazy danych”. Istnieją różne standardy SQL, ale żaden RDBMS nie jest w pełni zgodny. LIMIT
działa dla PostgreSQL i SQLite (i kilku innych). Użyj TOP 1
dla SQL Server, rownum
dla Oracle. Oto pełna lista w Wikipedii.
Standard SQL:2008 to:
...
FETCH FIRST 1 ROWS ONLY
... które obsługuje PostgreSQL - ale prawie żadnych innych RDBMS.
Czystą alternatywą, która działa z większą liczbą systemów, byłoby umieszczenie go w podzapytaniu i
SELECT max(total) FROM <subquery>
Ale to jest powolne i nieporęczne.
Skrzypce SQL.