版本:Oracle8I
实现下面功能,请问有什么高效一点的,不用临时表的方法谢谢!
(Oracle8I 里面有什么类似 sys_connect_by_path的函数?)
问题如下:
http://xxxtree.blog.sohu.com/22949969.html[转贴]BOM分解的过程累计运算方法标签: Oracle  BOM  
看到这个问题的讨论,就摘录下来。虽说看过后就得不难,倒有开拓思路之效。 
BOM 结构如图:
                                     A
                              B            C
                          D     E
                                 F
具体单位用量详见表 Bom
Parent        Child        Usage
A        B        2
A        C        3
B        D        2
B        E        3
E        F        5用  select P,   C,    U,
       LTRIM(sys_connect_by_path(P, '->'), '->'),
       LTRIM(sys_connect_by_path(U, '->'), '->')
  from bom
START WITH P = 'A'
CONNECT BY PRIOR C = P
可以得到如下的结果:
P        C        U        Path            Qty
A        B        2        A                  2
B        D        2        A->B              2->2
B        E        3        A->B              2->3
E        F        5        A->B->E          2->3->5
A        C        3        A                   3那位高手知道如何在sql里面将 qty 这一列乘起来或者直接用sql取出(如下表):
P        C        U        Path        Qty
A        B        2        A                  2
B        D        2        A->B              4
B        E        3        A->B              6
E        F        5        A->B->E          30
A        C        3        A                   3  方法一:对于这个问题, 我们是用一个函数实现的:CREATE OR REPLACE FUNCTION str_mult(p_str IN VARCHAR2) RETURN NUMBER
AS
    l_str VARCHAR2(1000):=p_str||'*';
    l_n   NUMBER;
    l_data NUMBER:=1;
BEGIN
    IF instr(l_str,'*')=1 THEN
       l_str:=SUBSTR(l_str,2);
    END IF;
    LOOP
          l_n:=instr(l_str,'*');
        EXIT WHEN (NVL(l_n,0)=0);
        l_data:=l_data*TO_NUMBER(SUBSTR(l_str,1,l_n-1));
        l_str:=SUBSTR(l_str,l_n+1);
    END LOOP;
    RETURN l_data;
END;如:
SQL> select * from test;PARE CHIL      USAGE
---- ---- ----------
A    B             2
A    C             3
B    D             2
B    E             3
E    F             5SQL> select Parent,   Child,    Usage,
  2         LTRIM(sys_connect_by_path(Parent, '->'), '->') fpath,
  3         LTRIM(sys_connect_by_path(Usage, '->'), '->') ausage,
  4         str_mult(sys_connect_by_path(Usage, '*')) quate
  5    from test
  6    START WITH Parent = 'A'
  7    CONNECT BY PRIOR Child = Parent;PARE CHIL      USAGE FPATH                          AUSAGE                              QUATE
---- ---- ---------- ------------------------------ ------------------------------ ----------
A    B             2 A                              2                                       2
B    D             2 A->B                           2->2                                    4
B    E             3 A->B                           2->3                                    6
E    F             5 A->B->E                        2->3->5                                30
A    C             3 A                              3                                       3   方法二:CREATE OR REPLACE FUNCTION GET_NUM(I_EXPRESSION IN VARCHAR2) RETURN NUMBER AS 
           TYPE CURSOR_REF_TYPE IS REF CURSOR;
           MY_CURSOR CURSOR_REF_TYPE;           V_NUM NUMBER;
           V_SQL VARCHAR2(200);
BEGIN
  V_SQL := 'SELECT ' || I_EXPRESSION || ' AS NUM FROM DUAL';
     
  OPEN MY_CURSOR FOR V_SQL;
  FETCH MY_CURSOR INTO V_NUM;
  
  RETURN V_NUM;
END;
  SELECT 
           PARENT,CHILD,USAGE,
           LTRIM(SYS_CONNECT_BY_PATH(PARENT,'->'),'->') FPATH,
           LTRIM(SYS_CONNECT_BY_PATH(USAGE,'->'),'->') AUSAGE,
           GET_NUM(LTRIM(SYS_CONNECT_BY_PATH(USAGE,'*'),'*')) QUATE
FROM
        TEST
START WITH PARENT = 'A'
CONNECT BY PRIOR CHILD = PARENT;  方法三:CREATE OR REPLACE FUNCTION GET_NUM(I_EXPRESSION IN VARCHAR2) RETURN NUMBER AS 
           TYPE CURSOR_REF_TYPE IS REF CURSOR;
           MY_CURSOR CURSOR_REF_TYPE;           V_NUM NUMBER;
           V_SQL VARCHAR2(200);
BEGIN
  EXECUTE IMMEDIATE 'SELECT ' || I_EXPRESSION || ' AS NUM FROM DUAL' INTO V_NUM;
  RETURN V_NUM;
END;
  SELECT 
           PARENT,CHILD,USAGE,
           LTRIM(SYS_CONNECT_BY_PATH(PARENT,'->'),'->') FPATH,
           LTRIM(SYS_CONNECT_BY_PATH(USAGE,'->'),'->') AUSAGE,
           GET_NUM(LTRIM(SYS_CONNECT_BY_PATH(USAGE,'*'),'*')) QUATE
FROM
        TEST
START WITH PARENT = 'A'
CONNECT BY PRIOR CHILD = PARENT;  方法四:V_SQL := 'SELECT :arg1 INTO :arg2 FROM DUAL';
EXECUTE IMMEDIATE V_SQL USING I_DISTANCE_ALL,OUT V_NUM; 本人从此处转贴:http://oraclespace.bokee.com/viewdiary.12977256.html

解决方案 »

  1.   

    很抱歉,8i没有类似sys_connect_by_path的函数
      

  2.   

    找到相关资料 分享sys_connect_by_path的几种处理方法标签: Oracle  
    1. 如果是Oracle9i以后的数据库版本, 可以直接使用sys_connect_by_path函数, 这是最简单的方式.
    SQL> col emp_name format a15
    SQL> col job format a10
    SQL> col scbp format a50
    SQL> select ename emp_name,job,sys_connect_by_path(ename,'/') scbp
      2  from emp
      3  start with mgr is null
      4  connect by prior empno = mgr
      5  /EMP_NAME        JOB        SCBP                                                 
    --------------- ---------- --------------------------------------------------   
    KING            PRESIDENT  /KING                                                
    JONES           MANAGER    /KING/JONES                                          
    SCOTT           ANALYST    /KING/JONES/SCOTT                                    
    ADAMS           CLERK      /KING/JONES/SCOTT/ADAMS                              
    FORD            ANALYST    /KING/JONES/FORD                                     
    SMITH           CLERK      /KING/JONES/FORD/SMITH                               
    BLAKE           MANAGER    /KING/BLAKE                                          
    ALLEN           SALESMAN   /KING/BLAKE/ALLEN                                    
    WARD            SALESMAN   /KING/BLAKE/WARD                                     
    MARTIN          SALESMAN   /KING/BLAKE/MARTIN                                   
    TURNER          SALESMAN   /KING/BLAKE/TURNER                                   
    JAMES           CLERK      /KING/BLAKE/JAMES                                    
    CLARK           MANAGER    /KING/CLARK                                          
    MILLER          CLERK      /KING/CLARK/MILLER                                   14 rows selected.SQL> spool off2.  使用table对象类型的数据显示. (From Tom).
    SQL> create or replace type myArrayType as table of varchar2(30)
      2  /Type created.SQL> select rpad('*',2*level,'*')|| ename emp_name, job,
      2         cast( multiset( select job
      3                         from emp e2
      4                         start with empno = emp.empno
      5                         connect by prior mgr = empno) as MyArrayType) scbp
      6  from emp
      7  start with mgr is null
      8  connect by prior empno = mgr
      9  /EMP_NAME        JOB        SCBP                                                 
    --------------- ---------- --------------------------------------------------   
    **KING          PRESIDENT  MYARRAYTYPE('PRESIDENT')                             
    ****JONES       MANAGER    MYARRAYTYPE('MANAGER', 'PRESIDENT')                  
    ******SCOTT     ANALYST    MYARRAYTYPE('ANALYST', 'MANAGER', 'PRESIDENT')       
    ********ADAMS   CLERK      MYARRAYTYPE('CLERK', 'ANALYST', 'MANAGER', 'PRESID   
                               ENT')                                                
                                                                                    
    ******FORD      ANALYST    MYARRAYTYPE('ANALYST', 'MANAGER', 'PRESIDENT')       
    ********SMITH   CLERK      MYARRAYTYPE('CLERK', 'ANALYST', 'MANAGER', 'PRESID   
                               ENT')                                                
                                                                                    
    ****BLAKE       MANAGER    MYARRAYTYPE('MANAGER', 'PRESIDENT')                  
    ******ALLEN     SALESMAN   MYARRAYTYPE('SALESMAN', 'MANAGER', 'PRESIDENT')      
    ******WARD      SALESMAN   MYARRAYTYPE('SALESMAN', 'MANAGER', 'PRESIDENT')      
    ******MARTIN    SALESMAN   MYARRAYTYPE('SALESMAN', 'MANAGER', 'PRESIDENT')      
    ******TURNER    SALESMAN   MYARRAYTYPE('SALESMAN', 'MANAGER', 'PRESIDENT')      
    ******JAMES     CLERK      MYARRAYTYPE('CLERK', 'MANAGER', 'PRESIDENT')         
    ****CLARK       MANAGER    MYARRAYTYPE('MANAGER', 'PRESIDENT')                  
    ******MILLER    CLERK      MYARRAYTYPE('CLERK', 'MANAGER', 'PRESIDENT')         14 rows selected.SQL> spool off
    3. Here is another 8i method, using a package by Solomon Yakobson: ( 理论上具体怎么说, 还不明白:-) 不过方法比较精巧. )SQL> @aaa.sql
    SQL> CREATE OR REPLACE
      2   PACKAGE Hierarchy
      3    IS
      4            TYPE BranchTableType IS TABLE OF VARCHAR2(4000)
      5          INDEX BY BINARY_INTEGER;
      6            BranchTable BranchTableType;
      7            FUNCTION Branch(vLevel         IN NUMBER,
      8                vValue         IN VARCHAR2,
      9                vDelimiter      IN VARCHAR2 DEFAULT CHR(0))
     10                RETURN VARCHAR2;
     11            PRAGMA RESTRICT_REFERENCES(Branch,WNDS);
     12  END Hierarchy;
     13  /Package created.SQL> 
    SQL> CREATE OR REPLACE
      2   PACKAGE BODY Hierarchy
      3    IS
      4            ReturnValue VARCHAR2(4000);
      5    FUNCTION Branch(vLevel          IN NUMBER,
      6              vValue       IN VARCHAR2,
      7              vDelimiter      IN VARCHAR2 DEFAULT CHR(0))
      8              RETURN VARCHAR2
      9       IS
     10       BEGIN
     11            BranchTable(vLevel) := vValue;
     12            ReturnValue := vValue;
     13            FOR I IN REVERSE 1..vLevel - 1 LOOP
     14          ReturnValue := BranchTable(I)|| vDelimiter || ReturnValue;
     15            END LOOP;
     16            RETURN ReturnValue;
     17    END Branch;
     18  END Hierarchy;
     19  /Package body created.SQL> select rpad('*',2 * level ,'*') || ename emp_name,job,
      2           hierarchy.branch (LEVEL, ename, '/') scbp
      3  from emp
      4  start with mgr is null
      5  connect by prior empno = mgr
      6  /EMP_NAME        JOB        SCBP                                                 
    --------------- ---------- --------------------------------------------------   
    **KING          PRESIDENT  KING                                                 
    ****JONES       MANAGER    KING/JONES                                           
    ******SCOTT     ANALYST    KING/JONES/SCOTT                                     
    ********ADAMS   CLERK      KING/JONES/SCOTT/ADAMS                               
    ******FORD      ANALYST    KING/JONES/FORD                                      
    ********SMITH   CLERK      KING/JONES/FORD/SMITH                                
    ****BLAKE       MANAGER    KING/BLAKE                                           
    ******ALLEN     SALESMAN   KING/BLAKE/ALLEN                                     
    ******WARD      SALESMAN   KING/BLAKE/WARD                                      
    ******MARTIN    SALESMAN   KING/BLAKE/MARTIN                                    
    ******TURNER    SALESMAN   KING/BLAKE/TURNER                                    
    ******JAMES     CLERK      KING/BLAKE/JAMES                                     
    ****CLARK       MANAGER    KING/CLARK                                           
    ******MILLER    CLERK      KING/CLARK/MILLER                                    14 rows selected.SQL> spool off