【问题标题】:Selecting positive aggregate value and ignoring negative in Postgres SQL在 Postgresql 中选择正聚合值并忽略负值
【发布时间】:2011-10-26 08:26:48
【问题描述】:

我必须应用某种转换fn(argument)。这里argument 等于value,但当它为负数时不等于。当你得到第一个负数value 时,你“等待”直到它与连续值相加并且这个总和变为正数。然后你做fn(argument)。查看我要获取的表:

价值论据 --------------------- 2 2 3 3 -10 0 4 0 3 0 10 7 1 1

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

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

【问题讨论】:

  • 您能否举例说明您正在寻找的语句的结果?我不确定你的确切目标是什么。
  • 输入是values和对应的fns。 IE。像(fn,值)这样的行。而且我必须根据上面描述的规则计算实际的 fn 参数。编辑:大声笑,当我写这个回复时,要求输入描述的初始评论已经消失。
  • 咪咕,问题中描述了结果。输入只是值,我必须计算参数。
  • 不要评论你的问题,编辑它们。

标签: sql postgresql aggregation window-functions


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    这并不真正适合任何预定义的聚合函数。您可能需要自己编写。请注意,在 postgresql 中,聚合函数可以用作窗口函数,事实上,这是在 C 以外的任何语言中编写窗口函数的唯一方法,截至 9.0。

    您可以编写一个函数来跟踪“求和”值的状态,但如果当前“求和”为正,则它总是返回输入值,而当“求和”为负时,它只会继续添加。然后你只需要取这个总和或零中的较大者。对白衣:

    -- 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);
    

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

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

    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
    >> \.
    

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

    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)
    

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

    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
    

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

    【讨论】:

    • greatest(value, 0) 正如 Nuno Rafael Figueiredo 所说,就足够了
    • 不,它不会产生 OP 指定的结果
    猜你喜欢
    • 2022-10-04
    • 2016-10-20
    • 1970-01-01
    • 2016-10-12
    • 2019-11-05
    • 2021-04-03
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    相关资源
    最近更新 更多