ORACLE 递归查询并累乘

ORACLE 数据库

一个数据表

PN_CODERAW_PN_CODEBASE_QTY
1000012000011
1000012000021
1000022000031
2000013000012
2000013000022
2000023000032
2000023000042
3000014000013
3000044000023

逻辑是:
如果只有一层,单只数量为第一层的 base_qty (1=SUM_QTY);
如果有两层,单只数量为第一层的 base_qty 第二层的 base_qty (12 =SUM_QTY);
如果有三层,单只用量为第一层的 base_qty 第二层的 base_qty 第三层的 base_qty (123=SUM_QTY);
以此类推

最终结果如下表

PN_CODERAW_PN_CODEBASE_QTYSUM_QTY
10000120000111
10000120000211
10000220000311
20000130000122
20000130000222
20000230000322
20000230000422
30000140000136
30000440000236

求SQL怎么实现。

1、开始以为是累加,最后才发现是累乘,这个需要一个自定义函数来辅助实现:
自定义函数:

CREATE OR REPLACE FUNCTION f_mm( a_mm IN VARCHAR2 ) RETURN NUMBER IS
    l_i    INT := 0;
    l_p    INT := 1;
    l_m    INT := 0;
    l_r    NUMBER := 1;
BEGIN
    IF TRIM( a_mm ) IS NULL THEN
        RETURN 0;
    END IF;
    l_i := INSTR( a_mm, '*' );
    IF l_i < 0 THEN
        RETURN to_number( a_mm, 'long' );
    END IF;
--    dbms_output.put_line( 'l_i = ' || l_i );
    WHILE ( l_i > 0 ) LOOP
--        dbms_output.put_line( 'l_i = ' || l_i || CHR( 9 ) || 'l_p = ' || l_p || CHR( 9 ) || 'l_m = ' || l_m || CHR( 9 ) || 'l_r = ' || l_r );
        l_m := SUBSTR( a_mm, l_p, l_i - l_p );
        l_r := NVL( to_number( l_m ), 1 ) * l_r; -- 连乘号或以乘号开头则默认为 1
        l_p := l_i + 1;
        l_i := INSTR( a_mm, '*', l_i + 1 );
    END LOOP;
--    dbms_output.put_line( 'l_i = ' || l_i || CHR( 9 ) || 'l_p = ' || l_p || CHR( 9 ) || 'l_m = ' || l_m || CHR( 9 ) || 'l_r = ' || l_r );
    
    RETURN l_r * ( CASE WHEN l_p <= LENGTH( a_mm ) THEN to_number( SUBSTR( a_mm, l_p, LENGTH( a_mm ) - l_p + 1 ) ) ELSE 1 END );
EXCEPTION
    WHEN OTHERS THEN
        dbms_output.put_line( 'Error!' );
        RETURN -999;
END;
/

然后再执行SQL:

WITH t AS (
    SELECT '100001' as PN_CODE, '200001' as RAW_PN_CODE, 1 as BASE_QTY FROM DUAL UNION ALL
    SELECT '100001' as PN_CODE, '200002' as RAW_PN_CODE, 1 as BASE_QTY FROM DUAL UNION ALL
    SELECT '100002' as PN_CODE, '200003' as RAW_PN_CODE, 1 as BASE_QTY FROM DUAL UNION ALL
    SELECT '200001' as PN_CODE, '300001' as RAW_PN_CODE, 2 as BASE_QTY FROM DUAL UNION ALL
    SELECT '200001' as PN_CODE, '300002' as RAW_PN_CODE, 2 as BASE_QTY FROM DUAL UNION ALL
    SELECT '200002' as PN_CODE, '300003' as RAW_PN_CODE, 2 as BASE_QTY FROM DUAL UNION ALL
    SELECT '200002' as PN_CODE, '300004' as RAW_PN_CODE, 2 as BASE_QTY FROM DUAL UNION ALL
    SELECT '300001' as PN_CODE, '400001' as RAW_PN_CODE, 3 as BASE_QTY FROM DUAL UNION ALL
    SELECT '300004' as PN_CODE, '400002' as RAW_PN_CODE, 3 as BASE_QTY FROM DUAL )
SELECT connect_by_root pn_code pn_code, connect_by_root raw_pn_code raw_pn_code
     , connect_by_root base_qty AS base_qty
     , f_mm( SYS_CONNECT_BY_PATH( base_qty, '*' ) ) sum_qty
  FROM t
 WHERE connect_by_isleaf = 1
CONNECT BY PRIOR pn_code = raw_pn_code;

执行结果为:

img

希望这个对你有帮助:使用Excel表格辅助分析,为复杂问题编写SQL https://blog.csdn.net/jerbo/article/details/130058874