9

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

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

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

我正在尝试类似的东西:

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

但是它似乎没有按预期工作,因为它实际上并没有对详细度列中的所有值求和。

我将非常感谢任何提示/帮助。

4

2 回答 2

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

这假设一个独特的、上升的,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;

递归 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;

所有标准 SQL,除了LIMIT.

严格来说,不存在“独立于数据库”之类的东西。有各种 SQL 标准,但没有一个 RDBMS 完全符合。LIMIT适用于 PostgreSQL 和 SQLite(以及其他一些)。用于TOP 1SQL Server,rownum用于 Oracle。这是Wikipedia 上的完整列表。

SQL:2008 标准将是:

...
FETCH  FIRST 1 ROWS ONLY

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

与更多系统一起使用的纯粹替代方法是将其包装在子查询中并

SELECT max(total) FROM <subquery>

但这是缓慢且笨拙的。

db<>fiddle here
sqlfiddle

于 2012-07-27T13:52:34.597 回答
1

这将工作...

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
)

但是,您应该了解 SQL 被设计为一种基于集合的语言,而不是一种迭代语言,因此它旨在将数据视为一个集合,而不是逐行处理。

于 2012-07-27T13:51:21.550 回答