You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复PL/SQL遍历Territory计算销售额时重复循环的问题

问题修复:PL/SQL循环Territory计算总销售额重复同一数据

你的代码核心问题有两个:

  • 内层游标CURSOR_2查询了所有Territory的订单明细,每次外层循环打开游标后会把所有记录遍历完,最终TERRITORY_ID和TERRITORY_DESC会停在最后一条记录的值,导致每次输出都是同一个Territory的数据。
  • 外层循环的T.TERRITORYID完全没起到过滤作用,内层游标没有关联当前循环的Territory,等于白遍历了外层的Territory列表。

修复方案一:带参数的游标(贴合你的循环思路)

把内层游标改成带参数的形式,每次只查询当前Territory的订单明细,让内外循环关联起来:

DECLARE
    TERRITORY_ID NUMBER(5);
    TERRITORY_DESC VARCHAR(50);
    NUMBER_SOLD NUMBER(5);
    UNIT_PRICE NUMBER(10);
    SUBTOTAL NUMBER(10);
    TOTAL NUMBER(10) := 0;
    
    -- 定义带参数的游标,接收当前TerritoryID做过滤
    CURSOR CURSOR_2(p_territory_id NUMBER) IS 
        SELECT T.TERRITORYID, T.TERRITORYDESCRIPTION, OD.QUANTITY, OD.UNITPRICE
        FROM TERRITORIES T
        JOIN ORDERS O ON T.TERRITORYID = O.TERRITORYID
        JOIN ORDERDETAILS OD ON O.ORDERID = OD.ORDERID
        WHERE T.TERRITORYID = p_territory_id;

BEGIN
    DBMS_OUTPUT.put_line('TERRITORY_ID' || '|' || 'TERRITORY_DESC' || '|' || 'TOTAL');
    
    -- 外层循环遍历所有Territory
    FOR t_rec IN (SELECT TERRITORYID, TERRITORYDESCRIPTION FROM TERRITORIES) LOOP
        TOTAL := 0;
        -- 打开游标时传入当前TerritoryID
        OPEN CURSOR_2(t_rec.TERRITORYID);
        LOOP 
            FETCH CURSOR_2 INTO TERRITORY_ID, TERRITORY_DESC, NUMBER_SOLD, UNIT_PRICE;
            EXIT WHEN CURSOR_2%NOTFOUND;
            SUBTOTAL := NUMBER_SOLD * UNIT_PRICE;
            TOTAL := TOTAL + SUBTOTAL;
        END LOOP;
        CLOSE CURSOR_2;
        
        -- 输出当前Territory的统计结果
        DBMS_OUTPUT.put_line(t_rec.TERRITORYID || '|' || t_rec.TERRITORYDESCRIPTION || '|' || TOTAL);
    END LOOP;
END;
/

修复方案二:直接用SQL聚合(更高效,推荐)

其实完全不需要嵌套游标,用SQL的GROUP BY就能直接完成聚合计算,代码更简洁且性能更好:

BEGIN
    DBMS_OUTPUT.put_line('TERRITORY_ID' || '|' || 'TERRITORY_DESC' || '|' || 'TOTAL');
    
    FOR rec IN (
        SELECT T.TERRITORYID, T.TERRITORYDESCRIPTION, SUM(OD.QUANTITY * OD.UNITPRICE) AS TOTAL_SALES
        FROM TERRITORIES T
        JOIN ORDERS O ON T.TERRITORYID = O.TERRITORYID
        JOIN ORDERDETAILS OD ON O.ORDERID = OD.ORDERID
        GROUP BY T.TERRITORYID, T.TERRITORYDESCRIPTION
    ) LOOP
        DBMS_OUTPUT.put_line(rec.TERRITORYID || '|' || rec.TERRITORYDESCRIPTION || '|' || rec.TOTAL_SALES);
    END LOOP;
END;
/

额外优化说明

  • 用显式JOIN代替老式逗号分隔表的写法,代码可读性更强。
  • 方案二利用数据库原生聚合函数,比游标循环的计算效率高很多,数据量越大优势越明显。

内容的提问来源于stack exchange,提问作者victor leung

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 18:35:27