n行的乘积

Lei*_*fel 6 oracle oracle-11g-r2

从这些数据(假设行数事先未知):

with q1 as (select mod(ora_hash(level),5) c1 from dual connect by level <=4)
select * from q1;
/*
C1
--
 2 
 1 
 4 
 1
*/
Run Code Online (Sandbox Code Playgroud)

我想要所有行的 c1 列的乘积。类似于 SUM(c1) 的结果,我希望每个值都乘以其他值而不是相加。在这种情况下,这将是 2 * 1 * 4 * 1 = 8。

/*
X1
--
 8
*/
Run Code Online (Sandbox Code Playgroud)

数据可能包含负数和零,可以使用以下方法进行模拟:

with q1 as (select mod(ora_hash(level),5)-1 c1 from dual connect by level <=4)
select * from q1;
Run Code Online (Sandbox Code Playgroud)

或者

with q1 as (select mod(ora_hash(level),5)-3 c1 from dual connect by level <=4)
select * from q1;
Run Code Online (Sandbox Code Playgroud)

我知道这可以通过自定义聚合函数来完成,但我对本机方法感兴趣。

Jus*_*ave 5

对于足够小的聚合产品,您可以使用对数求和并将结果取幂的老技巧

SQL> ed
Wrote file afiedt.buf

  1  with q1
  2    as (select mod(ora_hash(level),5) c1
  3          from dual
  4       connect by level <=4)
  5  select exp(sum(ln(c1)))
  6*   from q1
SQL> /

EXP(SUM(LN(C1)))
----------------
               8
Run Code Online (Sandbox Code Playgroud)

由于您使用的是 11.2,因此有点冗长(尽管有人可能会找出更简单的版本),但您也可以使用递归公用表表达式

SQL> ed
Wrote file afiedt.buf

  1  with
  2  q1 as (select level l, mod(ora_hash(level),5) c1
  3           from dual
  4        connect by level <= 4),
  5  num(n, c1, running_product)
  6  as
  7  (
  8    select 1 as N,
  9           null as c1,
 10           1 as running_product
 11      from dual
 12    union all
 13    select N+1,
 14           q1.c1,
 15           (q1.c1)*running_product
 16      from num
 17           join q1 on (num.N = q1.l)
 18  )
 19  select running_product
 20    from (select num.*,
 21                 rank() over (order by N desc) rnk
 22            from num)
 23*  where rnk = 1
SQL> /

RUNNING_PRODUCT
---------------
              8
Run Code Online (Sandbox Code Playgroud)