芋头阿 2023-04-15 21:59 采纳率: 100%
浏览 49
已结题

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怎么实现。

  • 写回答

2条回答 默认 最新

  • leaf_cq 2023-04-17 14:09
    关注

    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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 4月25日
  • 已采纳回答 4月17日
  • 创建了问题 4月15日

悬赏问题

  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改