2011-08-13 71 views
3

我必須應用某個轉換fn(argument)。這裏argument等於value,但不是負值時。當你得到第一個負數value,那麼你「等待」,直到它與連續值相加,這個總和變爲正值。然後你做fn(argument)。請參閱下表我想:在Postgres SQL中選擇正的聚合值並忽略負數

 
value  argument 
--------------------- 
    2   2  
    3   3  
-10   0  
    4   0 
    3   0 
    10   7 
    1   1 

我可以概括所有的值並應用fn的總和,但fn可以針對不同行不同,它是知道的行數必須選擇一個具體的FN 。

由於想要一個Postgres SQL解決方案,看起來像窗口函數合適,但我沒有足夠的經驗來編寫這樣做的表達式。實際上,我不熟悉「在sql中思考」。我想這可以通過一種必要的方式輕鬆完成,但我不想編寫存儲過程。

+1

你能給你要找的語句的結果的例子嗎?我不確定你的確切目標是什麼。 – migu

+0

輸入是值和對應的fns。即像(fn,value)這樣的行。我必須根據上述規則計算實際的fn論證。編輯:哈哈,正如我寫這個迴應,初始評論要求輸入描述已消失。 – zamza

+0

migu,結果在問題中描述。輸入只是數值,我必須計算參數。 – zamza

回答

1

這不符合任何預定義的聚合函數。你可能需要寫你自己的。請注意,在postgresql中,聚合函數可以用作窗口函數,事實上,這是從9.0開始編寫窗口函數的唯一方式,而不是C。

您可以編寫一個跟蹤「求和」值的函數,除非當前的「求和」爲正值時它總是返回輸入值,而當「求和」值爲負值時它會繼續添加。那麼你只需要採取這個總和或零的較大者。要白衣:

-- accumulator function: first arg is state, second arg is input 
create or replace function ouraggfunc(int, int) 
returns int immutable language plpgsql as $$ 
begin 
    raise info 'ouraggfunc: %, %', $1, $2; -- to help you see what's going on 
    -- get started by returning the first value ($1 is null - no state - first row) 
    if $1 is null then 
    return $2; 
    end if; 
    -- if our state is negative, we're summing until it becomes positive 
    -- otherwise, we're just returning the input 
    if $1 < 0 then 
    return $1 + $2; 
    else 
    return $2; 
    end if; 
end; 
$$; 

您需要創建一個聚合函數來調用這個蓄電池:

create aggregate ouragg(basetype = int, sfunc = ouraggfunc, stype = int); 

這意味着該骨料採用整數作爲輸入和存儲其狀態爲整數。

我複製你的榜樣到表:

[email protected]@[local] =# create table t(id serial primary key, value int not null, argument int not null); 
NOTICE: CREATE TABLE will create implicit sequence "t_id_seq" for serial column "t.id" 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "t_pkey" for table "t" 
CREATE TABLE 
[email protected]@[local] =# copy t(value, argument) from stdin; 
Enter data to be copied followed by a newline. 
End with a backslash and a period on a line by itself. 
>> 2 2 
>> 3 3 
>> -10 0 
>> 4 0 
>> 3 0 
>> 10 7 
>> 1 1 
>> \. 

,您現在可以通過使用聚合函數與窗口子句產生的這些值:

[email protected]@[local] =# select value, argument, ouragg(value) over(order by id) from t; 
INFO: ouraggfunc: <NULL>, 2 
INFO: ouraggfunc: 2, 3 
INFO: ouraggfunc: 3, -10 
INFO: ouraggfunc: -10, 4 
INFO: ouraggfunc: -6, 3 
INFO: ouraggfunc: -3, 10 
INFO: ouraggfunc: 7, 1 
value | argument | ouragg 
-------+----------+-------- 
    2 |  2 |  2 
    3 |  3 |  3 
    -10 |  0 | -10 
    4 |  0 |  -6 
    3 |  0 |  -3 
    10 |  7 |  7 
    1 |  1 |  1 
(7 rows) 

因此,大家可以看到,最後一步是如果函數的輸出是正數或零,那麼您需要輸出函數。這可以通過包裹查詢,或者寫一個函數來做到這一點來完成:

create function positive(int) returns int immutable strict language sql as 
$$ select case when $1 > 0 then $1 else 0 end $$; 

現在:

select value, argument, positive(ouragg(value) over(order by id)) as raw_agg from t 

這將產生論據,你在問題中所指定的功能。

+0

Nuno Rafael Figueiredo表示 – Controlix

+0

最大(值0)就足夠了,不會產生OP指定的結果 – araqnid

10

我想我遲到了,但是這可能幫助別人:

select 
    value, 
    greatest(0, value) as argument 
from your_table;