2011-02-18 30 views
16

好吧,这最初只是一个玩笑,我们曾与我的一个朋友,但它变成了有趣的技术问题:)过滤通过在PostgreSQL窗函数结果

我有以下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 

如果我删除此过滤器,总列得到正确计算,结果正确排序,但所有东西被选中,这不是我想要的。

那么,我该怎么做?我如何选择只能放入包内的物品?

回答

11

我还没有用过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; 
+0

这工作正常。但是,我想知道是否存在更优雅的解决方案。很奇怪,我无法直接基于“总计”进行筛选...... – 2011-02-18 15:20:57

+1

看起来WINDOW函数不能用于WHERE,HAVING子句(这也是Oracle在Oracle中的样子)。检查:http://www.postgresql.org/docs/current/static/tutorial-window.html – Chandu 2011-02-18 15:32:01

11

我不知道这是否有资格作为“更优雅”,但它是用不同的方式比Cyber​​nate的解决方案(虽然它在本质上是相同的)

 
WITH window_table AS 
( 
    SELECT s.*, 
      sum(volume) OVER previous_rows as total 
    FROM stuff s 
    WINDOW previous_rows as 
     (ORDER BY priority desc ROWS between UNBOUNDED PRECEDING and CURRENT ROW) 
) 
SELECT * 
FROM window_table 
WHERE total < 1000 
ORDER BY priority DESC 

如果“更多优雅“你的意思是避免子选择的东西,那么答案是”不“