sql >> データベース >  >> RDS >> PostgreSQL

フィールドの合計がN未満のSQL選択要素

    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(およびその他のいくつか)で動作します。 TOP 1を使用する SQL Serverの場合、rownum Oracleの場合。これがウィキペディアの包括的なリストです。

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

    ...
    FETCH  FIRST 1 ROWS ONLY
    

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

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

    することです。
    SELECT max(total) FROM <subquery>
    

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

    SQLフィドル。



    1. Postgresの既存の列に「シリアル」を追加する

    2. タイムゾーン付きのデータ型タイムスタンプでのタイムゾーンストレージ

    3. テーブル式の基礎、パート9 –ビュー、派生テーブルおよびCTEとの比較

    4. PostgreSQLDBの現在の接続数を取得するための正しいクエリ