在Postgres SQL中选择正聚合值并忽略否定

zam*_*mza 5 sql postgresql aggregation window-functions

我必须应用某种转变fn(argument).这argument等于value,但不是当它是负面的.当你得到第一个负数时value,那么你"等待"直到它与连续值相加并且这个总和变为正数.然后你做fn(argument).看到我想要的表格:

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

我可以将所有值求和并应用于fn总和,但fn对于不同的行可以有所不同,并且必须知道行号以选择具体的fn.

想要一个Postgres SQL解决方案,看起来像窗口函数适合,但我没有足够的经验来编写那样做的表达式.事实上,不幸的是,我是"思考sql"的新手.我想这可以通过命令式方式轻松完成,但我还不想编写存储过程.

Nun*_*edo 18

我想我迟到了,但这可能对某人有所帮助:

select
    value,
    greatest(0, value) as argument
from your_table;
Run Code Online (Sandbox Code Playgroud)


ara*_*nid 2

这并不真正适合任何预定义的聚合函数。您可能需要自己编写。请注意,在 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;
$$;
Run Code Online (Sandbox Code Playgroud)

您需要创建一个聚合函数来调用此累加器:

create aggregate ouragg(basetype = int, sfunc = ouraggfunc, stype = int);
Run Code Online (Sandbox Code Playgroud)

这定义了聚合将整数作为输入并将其状态存储为整数。

我将您的示例复制到表格中:

steve@steve@[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
steve@steve@[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
>> \.
Run Code Online (Sandbox Code Playgroud)

现在,您可以通过使用带有窗口子句的聚合函数来生成这些值:

steve@steve@[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)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,最后一步是您需要获取函数的输出(如果该输出为正或零)。这可以通过包装查询或编写一个函数来完成:

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

现在:

select value, argument, positive(ouragg(value) over(order by id)) as raw_agg from t
Run Code Online (Sandbox Code Playgroud)

这会生成您在问题中指定的函数的参数。