27

わかりました、最初はこれは私の友人との単なる冗談でしたが、興味深い技術的な質問になりました :)

次のstuff表があります。

CREATE TABLE stuff
(
    id serial PRIMARY KEY,
    volume integer NOT NULL DEFAULT 0,
    priority smallint NOT NULL DEFAULT 0,
);

テーブルには、それぞれのボリュームと優先度 (必要な量) とともに、すべてのアイテムのレコードが含まれています。

指定された容量のバッグがあります1000。バッグに入れることができるすべてのものをテーブルから選択し、最も重要なものを最初に詰めたい.

これはウィンドウ関数を使用する場合のように思われるので、私が思いついたクエリは次のとおりです。

select s.*, sum(volume) OVER previous_rows as total
 from stuff s
 where total < 1000
 WINDOW previous_rows as
  (ORDER BY priority desc ROWS between UNBOUNDED PRECEDING and CURRENT ROW)
 order by priority desc

ただし、問題は、Postgres が不平を言うことです。

ERROR:  column "total" does not exist
LINE 3:  where total < 1000

このフィルターを削除すると、合計列が適切に計算され、結果が適切に並べ替えられますが、すべてのものが選択されます。これは私が望んでいるものではありません。

それで、どうすればいいですか?バッグに収まる商品だけを選ぶにはどうすればよいですか?

4

2 に答える 2

20

これが「よりエレガント」であるかどうかはわかりませんが、Cyber​​nate のソリューションとは異なる方法で記述されています (本質的には同じですが)。

WITH window_table AS
(
   SELECT s.*,
          sum(volume) OVER previous_rows を合計として
   FROM スタッフ s
   WINDOW previous_rows as
        (ORDER BY priority desc ROWS between UNBOUNDED PRECEDING and CURRENT ROW)
)
選択する *
FROM window_table
WHERE 合計 < 1000
ORDER BY プライオリティ DESC

「よりエレガント」とは、サブセレクトを回避するものを意味する場合、答えは「いいえ」です

于 2011-02-18T17:23:39.287 に答える
18

私はPostgreSQLを使ったことがありません。ただし、私の最善の推測は、インラインビューを使用することです。

SELECT a.*
FROM (
    SELECT s.*, sum(volume) OVER previous_rows AS total
    FROM stuff AS s
    WINDOW previous_rows AS (
         ORDER BY priority desc
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    )
    ORDER BY priority DESC
) AS a
WHERE a.total < 1000;
于 2011-02-18T14:36:54.407 に答える