SQL选择元素,其中字段的总和小于N.

use*_*595 5 sql sqlite postgresql aggregate-functions sql-limit

鉴于我有一个包含以下内容的表,内容非常简单:

# select * from messages;
  id | verbosity 
 ----+-----------
   1 |        20
   2 |        20
   3 |        20
   4 |        30
   5 |       100
 (5 rows)
Run Code Online (Sandbox Code Playgroud)

我想选择N个消息,其中详细程度的总和低于Y(为了测试目的,假设它应该是70,那么正确的结果将是id为1,2,3的消息).这对我来说非常重要,该解决方案应该是独立于数据库的(至少应该在Postgres和SQLite上工作).

我试着用这样的东西:

SELECT * FROM messages GROUP BY id HAVING SUM(verbosity) < 70;
Run Code Online (Sandbox Code Playgroud)

但是它似乎没有按预期工作,因为它实际上并没有从详细列中汇总所有值.

我会非常感谢任何提示/帮助.

Erw*_*ter 16

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;
Run Code Online (Sandbox Code Playgroud)

这假设一个独特的,id像你在你的例子中提升.


在现代Postgres中 - 或者通常使用现代标准SQL(但不是在SQLite中):

简单的CTE

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

递归CTE

对于只检索小集的大表应该更快.

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;
Run Code Online (Sandbox Code Playgroud)

所有标准功能,除了LIMIT.

严格来说,没有"数据库独立"这样的东西.有各种SQL标准,但没有RDBMS完全符合.LIMIT适用于PostgreSQL和SQLite(以及其他一些).使用TOP 1的SQL Server,rownum用于Oracle.这是维基百科上的综合列表.

SQL:2008标准是:

...
FETCH  FIRST 1 ROWS ONLY
Run Code Online (Sandbox Code Playgroud)

... PostgreSQL支持哪种 - 但几乎没有任何其他RDBMS.

适用于更多系统的纯替代方案是将其包装在子查询中

SELECT max(total) FROM <subquery>
Run Code Online (Sandbox Code Playgroud)

但这是缓慢而笨拙的.

SQL小提琴.