您的位置:首页 > 数据库 > Oracle

Oracle聚合求和和聚合求积(顺便解决BOM展开的问题)

2013-11-17 21:14 531 查看
本文参考网址:http://www.itpub.net/thread-1020772-1-1.html

我们在日常的工作中,经常遇到了针对某一列的值,进行求和,求平均值,在一些特殊的业务场景下,我们需要对某一列进行求积操作,那我们该如何实现呢,下面先介绍,我

们对字符串的求和操作。

针对字符串的求和操作:

1、有分隔符的字符串:

SELECT STR, SUM(STR) OVER(ORDER BY LV ASC) AS RS
FROM (SELECT REGEXP_SUBSTR('1,2,3,4,5', '[^,]+', 1, LEVEL) AS STR,
LEVEL AS LV
FROM DUAL
CONNECT BY LEVEL <=
LENGTH(REGEXP_REPLACE('1,2,3,4,5', '[^,]', '')) + 1) COLS


结果:



2、没有分割符符号的:

SELECT STR, SUM(STR) OVER(ORDER BY LV ASC) AS RS
FROM (SELECT SUBSTR('12345', LEVEL, 1) STR, LEVEL AS LV
FROM DUAL
CONNECT BY LEVEL <= LENGTH(12345)) COLS


结果:



下面介绍连续求积的方法

SUM()是个求和的聚合函数,如何求积呢?我们可以想办法把乘法变成加法:

A*B*C = 10^(LOG(A)+LOG(B)+LOG(C))

1、直接使用对数和反对数来进行求积,即:LOG和POWER函数

SELECT STR, POWER(10, SUM(LOG(10, STR)) OVER(ORDER BY STR))
FROM (SELECT REGEXP_SUBSTR('1,2,3,4,5', '[^,]+', 1, LEVEL) AS STR,
LEVEL AS LV
FROM DUAL
CONNECT BY LEVEL <=
LENGTH(REGEXP_REPLACE('1,2,3,4,5', '[^,]', '')) + 1) COLS


结果:



2、使用PL/SQL的自定义函数来实现该功能

CREATE OR REPLACE FUNCTION GET_EXPRESSION_RSLT(I_EXPRESSION VARCHAR2) RETURN VARCHAR2 IS
/************************************************************
* 函数名称:GET_EXPRESSION_RSLT
* 功能描述:获取指定的表达式的结果
* 参数:I_EXPRESSION :表达式  例如:1*2*3
* 编 写 人:XXX
* 编写时间:XXXX-XX-XX
* 修改记录:
*************************************************************/
RETURNSTR VARCHAR2(500) := '';
EXECSQL   VARCHAR2(4000) := '';
BEGIN
EXECSQL := ' SELECT ' || I_EXPRESSION || '  FROM  DUAL';
EXECUTE IMMEDIATE (EXECSQL)
INTO RETURNSTR;
RETURN RETURNSTR;
END;


SQL:

SELECT STR,
GET_EXPRESSION_RSLT(REPLACE(WM_CONCAT(STR) OVER(ORDER BY STR),
',',
'*')) RS
FROM (SELECT REGEXP_SUBSTR('1,2,3,4,5', '[^,]+', 1, LEVEL) AS STR,
LEVEL AS LV
FROM DUAL
CONNECT BY LEVEL <=
LENGTH(REGEXP_REPLACE('1,2,3,4,5', '[^,]', '')) + 1) COLS


结果:



但是,使用这种方法:newid这个大拿给出了不使用该种方法的建议:

SELECT A*B*C... FROM DUAL;

都是常量且个数不定,每次都需要硬解析,所以不推荐。

下面是tom对使用wm_concat函数的看法:

http://asktom.oracle.com/pls/ask ... #548923200346634568

Hi Tom,

I saw wm_concat on a couple of forums (otn and orafaq), apparently a new, undocumented function as
shown below. Since it is undocumented, is it safe to use?

Regards,
Barbara

Followup November 20, 2007 - 2pm US/Eastern:

my suggestion is going to be consistent....

Never use undocumented stuff, it is subject to change, removal, broken-ness without recourse.

either

a) use stragg
b) write your own
c) use the connect by trick.

3、使用自定义的聚合函数

安德森

CREATE OR REPLACE TYPE PROD_AGG_TYPE AS OBJECT
(
TOTAL NUMBER,

STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT PROD_AGG_TYPE)
RETURN NUMBER,

MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF  IN OUT PROD_AGG_TYPE,
VALUE IN NUMBER) RETURN NUMBER,

MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF        IN PROD_AGG_TYPE,
RETURNVALUE OUT NUMBER,
FLAGS       IN NUMBER)
RETURN NUMBER,

MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT PROD_AGG_TYPE,
CTX2 IN PROD_AGG_TYPE) RETURN NUMBER
)
/
CREATE OR REPLACE TYPE BODY PROD_AGG_TYPE IS

STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT PROD_AGG_TYPE)
RETURN NUMBER IS
BEGIN
SCTX       := PROD_AGG_TYPE(NULL);
SCTX.TOTAL := 1;
RETURN ODCICONST.SUCCESS;
END;

MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF  IN OUT PROD_AGG_TYPE,
VALUE IN NUMBER) RETURN NUMBER IS
BEGIN
SELF.TOTAL := SELF.TOTAL * VALUE;
RETURN ODCICONST.SUCCESS;
END;

MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF        IN PROD_AGG_TYPE,
RETURNVALUE OUT NUMBER,
FLAGS       IN NUMBER) RETURN NUMBER IS
BEGIN
RETURNVALUE := SELF.TOTAL;
RETURN ODCICONST.SUCCESS;
END;

MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT PROD_AGG_TYPE,
CTX2 IN PROD_AGG_TYPE) RETURN NUMBER IS
BEGIN
SELF.TOTAL := SELF.TOTAL * CTX2.TOTAL;
RETURN ODCICONST.SUCCESS;
END;

END;
/


函数:

CREATE OR REPLACE FUNCTION prod_agg(input NUMBER )
RETURN NUMBER
PARALLEL_ENABLE AGGREGATE USING prod_agg_type;


SQL:

SELECT STR, prod_agg(STR) OVER(ORDER BY LV ASC) AS RS
FROM (SELECT SUBSTR('12345', LEVEL, 1) STR, LEVEL AS LV
FROM DUAL
CONNECT BY LEVEL <= LENGTH(12345)) COLS


结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: