2010-08-25 300 views
1

假設我的subquery產生了包含列(x,y)的許多行,我想計算值avg(abs(x-mean)/y)。其中mean實際上是avg(x)避免在PostgreSQL中嵌套聚合函數8.3.4

select avg(abs(x-avg(x))/y) as incline from subquery失敗,因爲我無法嵌套聚合函數。我也不能想到一種方法來計算子查詢中的均值,同時保留原始結果集。其他方言中存在的avgdev函數並不能完全幫助我,所以在這裏我被卡住了。可能僅僅是由於缺乏SQL知識 - 在後處理中計算結果集中的值很容易。

哪個SQL構造可以幫助我?

編輯:服務器版本是8.3.4。這裏沒有窗口功能WITHOVER

+0

我想這個問題是......如果你真的,真的需要這種行爲...是否有一個原因,你不能得到推動升級? – xenoterracide 2010-08-25 12:54:23

+1

當depesz做他的'等待'系列時,他有時會顯示以前的做法......你可能想看看他在等待窗口函數或類似的東西。 – xenoterracide 2010-08-25 12:56:31

+0

那會是這樣一個:http://www.depesz.com/index.php/2009/01/21/waiting-for-84-window-functions/ - 感謝那個指針。 – relet 2010-08-25 13:18:44

回答

0

一種選擇,我發現是使用臨時表:

begin; 
    create temporary table sub on commit drop as (...subquery code...); 
    select avg(abs(x-mean)/y) as incline from (SELECT x, y, (SELECT avg(x) FROM sub) AS mean FROM sub) as sub2; 
commit; 

但是,這是矯枉過正?

+2

您不需要臨時表,只需將子查詢代碼放在您擁有該表的相同位置 – 2010-12-08 17:37:47

1

不知道我理解你正確,但你可能會尋找這樣的事情:

SELECT avg(x - mean/y) 
FROM (
    SELECT x, 
     y, 
     avg(x) as mean over(partition by your_grouping_column) 
    FROM your_table 
) t 

如果你不需要將你的結果,以獲得正確的AVG(X),然後簡單地離開了使用空過「的分區」:over()

+0

'select x,y,avg(x)作爲平均over()from(..my subquery here ..)as sub;'在'over'處出現'ERROR:syntax error at or near'over' – relet 2010-08-25 11:20:27

+1

窗口功能似乎是8.4功能,我查詢的服務器是8.3.4。不管怎麼說,還是要謝謝你。 :] – relet 2010-08-25 11:46:34

+2

這是你應該始終提到你的Postgres版本的重要之一;) – 2010-08-25 13:13:09

1

如果你的數據集不是太大,你可以積累他們到一個數組,然後從一個函數返回傾斜:測試

create type typ as (x numeric, y numeric); 

create aggregate array_accum(sfunc = array_append, 
           basetype = anyelement, 
           stype = anyarray, 
           initcond = '{}'); 

create or replace function unnest(anyarray) returns setof anyelement 
          language sql immutable strict as $$ 
    select $1[i] from generate_series(array_lower($1,1), array_upper($1,1)) i;$$; 

create function get_incline(typ[]) returns numeric 
       language sql immutable strict as $$ 
    select avg(abs(x-(select avg(x) from unnest($1)))/y) from unnest($1);$$; 

select get_incline((select array_accum((x,y)::typ) from subquery)); 

樣的看法:

create view subquery as 
select generate_series(1,5) as x, generate_series(1,6) as y;