聚合函数将所有值相乘

时间:2019-06-07 07:35:57

标签: sql oracle

例如我有这样的数据

1
2
3
4
5

如何将每一行相乘?是否有类似于SUM()的函数,因此在此示例中答案为120。

3 个答案:

答案 0 :(得分:3)

是的,this blog中描述了一种技术:

基本上,您采用自然对数SUM,然后进行指数(e^x

SELECT EXP (SUM (LN (col))) as product from t;

由于此输出将是浮点,因此您可以执行FLOOR

FLOOR( EXP (SUM (LN (col))) ) 

DEMO

注意:我刚刚发现,如果其中一行包含0,这将失败。因此,您应该使用单独的条件或with子句,如果其中一个为零,则乘积应为零。

答案 1 :(得分:2)

这很少使用,但是oracle使您可以定义自定义的聚合函数。 您要做的就是创建一个实现ODCIAggregate方法的类型,然后创建使用该类型的函数。

oracle docs中有一个示例,请参见“示例11-12如何创建和使用用户定义的聚合函数”一节。

我基本上已经复制了示例并更改了几行:

create or replace type AGGR_MUL_TST as object
(
  total number,
  static function ODCIAggregateInitialize(ctx IN OUT AGGR_MUL_TST) 
  return number,
  member function ODCIAggregateIterate(self IN OUT AGGR_MUL_TST, 
                                       value IN number) 
  return number,
  member function ODCIAggregateTerminate(self IN AGGR_MUL_TST, 
                                         returnValue OUT number, flags IN number) 
  return number,
  member function ODCIAggregateMerge(self IN OUT AGGR_MUL_TST, 
                                     ctx2 IN AGGR_MUL_TST) 
  return number
);


create or replace type body AGGR_MUL_TST is
   static function ODCIAGGREGATEINITIALIZE(ctx in out AGGR_MUL_TST)
   return number is
   begin
      ctx := AGGR_MUL_TST(1);
      return ODCIConst.Success;
   end;

   member function ODCIAggregateIterate(self in out AGGR_MUL_TST,
                                        value in number)
   return number is
   begin
      self.total := self.total * value;
      return ODCIConst.Success;
   end;

   member function ODCIAggregateTerminate(self in AGGR_MUL_TST,
                                          returnValue out number,
                                          flags in number
                                         )
   return number is
   begin
      returnValue := self.total;
      return ODCIConst.Success;
   end;

   member function ODCIAggregateMerge(self in out AGGR_MUL_TST,
                                      ctx2 IN AGGR_MUL_TST
                                     )
   return number is
   begin
     self.total := self.total * ctx2.total;
  end;
end;
/
create or replace function AGGR_MUL(input number) return number parallel_enable aggregate using AGGR_MUL_TST;
/

现在,您可以在任何查询中使用它,例如常规的聚合函数:

with nums as (
   select 1 x, 2 y from dual union all
   select 2 x, 2 y from dual union all
   select 3 x,  2 y from dual union all
   select 4 x,  3 y from dual union all
   select -5 x, 3 y from dual
)
select aggr_mul(x)
  from nums

甚至分组依据:

with nums as (
   select 1 x, 2 y from dual union all
   select 2 x, 2 y from dual union all
   select 3 x,  2 y from dual union all
   select 4 x,  3 y from dual union all
   select -5 x, 3 y from dual
)
select y,
       aggr_mul(x)
  from nums
group by y

答案 2 :(得分:1)

一般的解决方案要复杂一些-处理零和负数。

select (exp(sum(ln(abs(nullif(col, 0))))) *
        (1 - 2 * mod(sum(case when col < 0 then 1 when col = 0 then 0.5 else 0 end), 2)
       ) as product 
  • nullif()处理0,因此ln()不会返回错误。
  • abs()处理负数,因此ln()不会返回错误。
  • case表达式处理结果上的符号,如果任何值为零,则也返回零。