9

次の非常に単純なコンテンツを含むテーブルがあるとすると、次のようになります。

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

冗長性の合計がYよりも小さいN個のメッセージを選択したいと思います(テスト目的で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が完全に準拠しているわけではありません。LIMITPostgreSQLとSQLite(およびその他のいくつか)で動作します。TOP 1SQL Server、 Oracleに使用しrownumます。これがウィキペディアの包括的なリストです。

SQL:2008標準は次のようになります。

...
FETCH  FIRST 1 ROWS ONLY

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

より多くのシステムで機能する純粋な代替手段は、サブクエリでラップし、

SELECT max(total) FROM <subquery>

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

db <> fiddle here
Old 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 に答える