質問

次のようなテーブルを持っていること、非常に単純なコンテンツ:

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

私はN個のメッセージを選択したい、どのverboityの合計はyより低い(テスト目的のためにそれが70になるべきであると言うと、正しい結果はID 1,2,3のメッセージになります)。 その解決策はデータベースに依存しないはずです(少なくともPostgresとSQLiteで動作する必要があります)。

私は次のようなもので試していました:

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

しかしそれは実際には冗長列からのすべての値を合計しないので、予想通りに動作していないようです。

私はあらゆるヒント/ヘルプに非常に感謝します。

役に立ちましたか?

解決

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

LIMIT を除くすべての標準機能。

厳密に言えば、「データベースに依存しない」ということはありません。さまざまなSQL規格がありますが、RDBMSは完全に準拠していません。 LIMITはPostgreSQLとSQLite(そして他の何人か)に機能します。 Oracle用のTOP 1 for SQL Server用のrownumを使用します。これは、ウィキペディアの包括的なリストです。

SQL:2008標準は次のとおりです。

...
FETCH  FIRST 1 ROWS ONLY
.

...どのPostgreSQLがサポートしています - 他のRDBMSはほとんどありません。

より多くのシステムで動作する純粋な代替案は、それを副照会で包み、

を描くことです。
SELECT max(total) FROM <subquery>
.

しかしそれは遅く、扱いにくいです。

SQLフィドル

他のヒント

これはうまくいきます...

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は、反復的なものではなくセットに基づく言語として設計されているので、行ごとに1行ではなくセットとしてデータを扱うように設計されています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top