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;
Điều này giả định một id
duy nhất, tăng dần như bạn có trong ví dụ của bạn.
Trong Postgres hiện đại - hoặc nói chung với SQL tiêu chuẩn hiện đại (nhưng không trong SQLite):
CTE đơn giản
WITH cte AS (
SELECT *, sum(verbosity) OVER (ORDER BY id) AS total
FROM messages
)
SELECT *
FROM cte
WHERE total <= 70
ORDER BY id;
CTE đệ quy
Sẽ nhanh hơn đối với các bảng lớn, nơi bạn chỉ truy xuất một nhóm nhỏ.
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;
Tất cả các tính năng tiêu chuẩn, ngoại trừ LIMIT
.
Nói một cách chính xác, không có cái gọi là "độc lập với cơ sở dữ liệu". Có nhiều tiêu chuẩn SQL khác nhau, nhưng không có RDBMS nào tuân thủ hoàn toàn. LIMIT
hoạt động cho PostgreSQL và SQLite (và một số khác). Sử dụng TOP 1
cho SQL Server, rownum
cho Oracle. Đây là danh sách đầy đủ trên Wikipedia.
Tiêu chuẩn SQL:2008 sẽ là:
...
FETCH FIRST 1 ROWS ONLY
... mà PostgreSQL hỗ trợ - nhưng hầu như không có RDBMS nào khác.
Giải pháp thay thế thuần túy hoạt động với nhiều hệ thống hơn sẽ là gói nó trong một truy vấn con và
SELECT max(total) FROM <subquery>
Nhưng nó chậm và khó sử dụng.
SQL Fiddle.