Product()聚合函数

时间:2014-02-01 15:15:47

标签: sql oracle statistics

在解释CTE的一些概念时,我们问了一个可爱的问题......我们能找到行的乘法,而我们总是专注于SUM()来自更新。这给了我一个想法!只用SQL就可以实现。我也在考虑我们甚至可以支持的最大数量精度,因为产品可能非常庞大。

话虽如此,我们无法编写自己的聚合函数。(我们可以吗?)我想只有SQL才能实现。

我认为2*3就像在自己身上添加2,3次......但是当这个集合很大时......我无法让它成为可能,因为它可能很麻烦。

其他可能性为log (a+b) = log a * log b;Anti logarithm,为您提供结果。这就是我设法回应的内容。对于Oracle,我将使用EXECUTE IMMEDIATE

我们真的可以自我繁衍。这将是更美丽的SQL-ly ..这是纯粹的学习经验。

3 个答案:

答案 0 :(得分:9)

logarathm / power方法是常用的方法。对于Oracle,即:

select exp(sum(ln(col)))
from table;

我不知道为什么原始数据库设计者没有将PRODUCT()作为聚合函数包含在内。我最好的猜测是他们都是计算机科学家,没有统计学家。这些功能在统计学中非常有用,但它们在计算机科学中并不多见。也许他们并不想处理溢出问题,这样的函数会暗示(特别是整数)。

顺便说一下,大多数数据库都缺少这个功能,即使那些实现了大量统计聚合功能的数据库也是如此。

编辑:

Oy,负数问题使它更复杂一些:

select ((case when mod(sum(sign(col)), 2) = 0 then 1 else -1 end) *
        exp(sum(ln(abs(col))))
       ) as product

我不确定在Oracle中处理0的安全方法。这是一个"逻辑"的方法:

select (case when sum(case when col = 0 then 1 else 0 end) > 0
             then NULL
             when mod(sum(sign(col)), 2) = 0
             then exp(sum(ln(abs(col)))
             else - exp(sum(ln(abs(col)))
        end) 
       ) as product

问题是数据库引擎在执行case语句之前可能会在日志上出错。这恰好是SQL Server的工作原理。我不确定Oracle。

啊,这可能有用:

select (case when sum(case when col = 0 then 1 else 0 end) > 0
             then NULL
             when mod(sum(sign(col)), 2) = 0
             then exp(sum(ln(case when col <> 0 then abs(col) end)))
             else - exp(sum(ln(case when col <> 0 then abs(col) end)))
        end) 
       ) as product

如果有NULL,则返回0

答案 1 :(得分:5)

在Oracle中,您可以创建自己的聚合函数,
请看一下这个工作示例:http://sqlfiddle.com/#!4/ee247/1
它基于文档中的示例:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28425/aggr_functions.htm

create type ProductImpl as object
(
  product NUMBER, 
  static function ODCIAggregateInitialize(sctx IN OUT ProductImpl) return number,
  member function ODCIAggregateIterate(self IN OUT ProductImpl, value IN number) return number,
  member function ODCIAggregateTerminate(self IN ProductImpl, returnValue OUT number, flags IN number) return number,
  member function ODCIAggregateMerge(self IN OUT ProductImpl, ctx2 IN ProductImpl) return number
);
/

create or replace type body ProductImpl is 
static function ODCIAggregateInitialize(sctx IN OUT ProductImpl) 
return number is 
begin
  sctx := ProductImpl(1);
  return ODCIConst.Success;
end;

member function ODCIAggregateIterate(self IN OUT ProductImpl, value IN number) return number is
begin
  self.Product := self.Product * value;
  return ODCIConst.Success;
end;

member function ODCIAggregateTerminate(self IN ProductImpl, 
    returnValue OUT number, flags IN number) return number is
begin
  returnValue := self.Product;
  return ODCIConst.Success;
end;

member function ODCIAggregateMerge(self IN OUT ProductImpl, ctx2 IN ProductImpl) return number is
begin
  self.Product := self.Product * ctx2.Product;
  return ODCIConst.Success;
end;
end;
/

CREATE OR REPLACE FUNCTION Product (input NUMBER) RETURN NUMBER 
PARALLEL_ENABLE AGGREGATE USING ProductImpl;
/

答案 2 :(得分:3)

Oracle公开了这些ODCI(Oracle数据盒式磁带接口)方法来进行聚合! Reference

  • ODCIAggregateDelete() - 从当前组中删除输入值。
  • ODCIAggregateInitialize() - 初始化实现对象类型的聚合上下文和实例,并将其作为OUT参数返回。
  • ODCIAggregateIterate() - 通过处理输入值,更新然后返回聚合上下文来迭代输入行。
  • ODCIAggregateMerge() - 在对用户定义的聚合进行串行或并行评估期间,将两个聚合上下文合并为一个对象实例。
  • ODCIAggregateTerminate() - 计算聚合计算的结果并执行所有必要的清理,例如释放内存。
  • ODCIAggregateWrapContext()集成当前聚合上下文的所有外部部分,以使上下文自包含。

PRODUCT代码()聚合函数:

CREATE OR REPLACE type PRODUCT_IMPL
AS
  object
  (
    result NUMBER,
    static FUNCTION ODCIAggregateInitialize(sctx IN OUT PRODUCT_IMPL)
    RETURN NUMBER,
    member FUNCTION ODCIAggregateIterate(self  IN OUT PRODUCT_IMPL,
                                         value IN NUMBER)
    RETURN NUMBER,
    member FUNCTION ODCIAggregateTerminate( self IN PRODUCT_IMPL,
                                            returnValue OUT NUMBER,
                                            flags IN NUMBER)
    RETURN NUMBER,
    member FUNCTION ODCIAggregateMerge(self IN OUT PRODUCT_IMPL,
                                       ctx2 IN PRODUCT_IMPL )
    RETURN NUMBER );
  /
  /* 1.Initializes the computation by initializing the aggregation context—the rows over which aggregation is performed: */
CREATE OR REPLACE type body PRODUCT_IMPL
IS
  static FUNCTION ODCIAggregateInitialize(sctx IN OUT PRODUCT_IMPL)
  RETURN NUMBER
IS
BEGIN
  sctx := PRODUCT_IMPL(1);
  RETURN ODCIConst.Success;
END;
/* 2.Iteratively processes each successive input value and updates the context: */
member FUNCTION ODCIAggregateIterate(self  IN OUT PRODUCT_IMPL,
                                     value IN NUMBER)
  RETURN NUMBER
IS
BEGIN
  self.result := value * self.result;
  RETURN ODCIConst.Success;
END;
member FUNCTION ODCIAggregateTerminate(
    self IN PRODUCT_IMPL,
    returnValue OUT NUMBER,
    flags IN NUMBER)
  RETURN NUMBER
IS
BEGIN
  returnValue := self.result;
  RETURN ODCIConst.Success;
END;
member FUNCTION ODCIAggregateMerge(self IN OUT PRODUCT_IMPL,
                                   ctx2 IN PRODUCT_IMPL)
  RETURN NUMBER
IS
BEGIN
  self.result := self.result;
  RETURN ODCIConst.Success;
END;
END;
/

/* Create A function using the PRODUCT_IMPL implementation we did above */
CREATE OR REPLACE FUNCTION product(input NUMBER)
RETURN NUMBER 
PARALLEL_ENABLE AGGREGATE USING PRODUCT_IMPL;
/

<强>结果:

SELECT group_name,product(num) FROM product_test GROUP BY group_name;

Mahesh  -60000
Mahesh_1    9