例如我有这样的数据
1
2
3
4
5
如何将每一行相乘?是否有类似于SUM()
的函数,因此在此示例中答案为120。
答案 0 :(得分:3)
是的,this blog中描述了一种技术:
基本上,您采用自然对数SUM
,然后进行指数(e^x
)
SELECT EXP (SUM (LN (col))) as product from t;
由于此输出将是浮点,因此您可以执行FLOOR
FLOOR( EXP (SUM (LN (col))) )
注意:我刚刚发现,如果其中一行包含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
表达式处理结果上的符号,如果任何值为零,则也返回零。