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

PL/SQL循环执行时触发No Data Found错误的排查求助

解决PL/SQL中SELECT INTO的NO_DATA_FOUND错误

你遇到的NO_DATA_FOUND错误,核心原因是SELECT INTO语句强制要求返回且仅返回1行数据——如果某个查询没有匹配到任何记录,PL/SQL就会抛出这个异常。比如循环到某个customertrxid时,TrasladosTotal表中没有对应0.03税率的记录,对应的SELECT IMPORTE into ImporteTotal03...就会触发错误。

下面给你三种可行的解决思路:


1. 捕获NO_DATA_FOUND异常,给变量赋默认值

在每个可能无数据的SELECT INTO外层加异常处理,触发异常时给变量设默认值(比如0或NULL),避免程序中断:

DECLARE
    current_id       Comprobante.customertrxid%TYPE;
    SumaImporteCon   NUMBER := 0;
    Subtotal         NUMBER := 0;
    SumaTasa03       NUMBER := 0;
    ImporteTotal03   NUMBER := 0;
    SumaTasa16       NUMBER := 0;
    ImporteTotal16   NUMBER := 0;
    SumaImpuesto     NUMBER := 0;
    ImpuestoTotal    NUMBER := 0;
BEGIN
    FOR id_rec IN (SELECT customertrxid FROM comprobante) LOOP
        current_id := id_rec.customertrxid;
        DBMS_OUTPUT.PUT_LINE('ID: ' || current_id);
        
        -- 处理Conceptos表查询
        BEGIN
            SELECT sum(IMPORTE) INTO SumaImporteCon 
            FROM Conceptos 
            WHERE customertrxid = current_id;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                SumaImporteCon := 0;
        END;
        
        -- 处理Comprobante表查询
        BEGIN
            SELECT SUBTOTAL INTO Subtotal 
            FROM Comprobante 
            WHERE customertrxid = current_id;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                Subtotal := 0;
        END;
        
        -- 处理Traslados 0.03税率查询
        BEGIN
            SELECT sum(IMPORTE) INTO SumaTasa03 
            FROM Traslados 
            WHERE TasaOcuota = '0.030000' AND customertrxid = current_id;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                SumaTasa03 := 0;
        END;
        
        -- 处理TrasladosTotal 0.03税率查询
        BEGIN
            SELECT IMPORTE INTO ImporteTotal03 
            FROM TrasladosTotal 
            WHERE TasaOcuota = '0.030000' AND customertrxid = current_id;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                ImporteTotal03 := 0;
        END;
        
        -- 处理Traslados 0.16税率查询
        BEGIN
            SELECT sum(IMPORTE) INTO SumaTasa16 
            FROM Traslados 
            WHERE TasaOcuota = '0.160000' AND customertrxid = current_id;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                SumaTasa16 := 0;
        END;
        
        -- 处理TrasladosTotal 0.16税率查询
        BEGIN
            SELECT IMPORTE INTO ImporteTotal16 
            FROM TrasladosTotal 
            WHERE TasaOcuota = '0.160000' AND customertrxid = current_id;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                ImporteTotal16 := 0;
        END;
        
        -- 处理TrasladosTotal总税额查询
        BEGIN
            SELECT sum(IMPORTE) INTO SumaImpuesto 
            FROM TrasladosTotal 
            WHERE customertrxid = current_id;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                SumaImpuesto := 0;
        END;
        
        -- 处理ImpuestosTotal总税额查询
        BEGIN
            SELECT TOTALIMPUESTOSTRASLADOS INTO ImpuestoTotal 
            FROM ImpuestosTotal 
            WHERE customertrxid = current_id;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                ImpuestoTotal := 0;
        END;
        
        -- 输出对比结果
        dbms_output.put_line('Suma importe conceptos ' || SumaImporteCon);
        dbms_output.put_line('Subtotal Comprobante: ' || Subtotal);
        IF (SumaImporteCon = Subtotal) THEN
            dbms_output.put_line('SI coinciden');
        ELSE
            dbms_output.put_line('NO coinciden');
        END IF;
        
        dbms_output.put_line('Suma tasa 0.03: ' || SumaTasa03);
        dbms_output.put_line('Importe 0.03: ' || ImporteTotal03);
        IF ( SumaTasa03 = ImporteTotal03) THEN
            dbms_output.put_line('SI coinciden');
        ELSE
            dbms_output.put_line('NO coinciden');
        END IF;
        
        dbms_output.put_line('Suma tasa 0.16: ' || SumaTasa16);
        dbms_output.put_line('Importe 0.16: ' || ImporteTotal16);
        IF (SumaTasa16 = ImporteTotal16) THEN
            dbms_output.put_line('SI coinciden');
        ELSE
            dbms_output.put_line('NO coinciden');
        END IF;
        
        dbms_output.put_line('Suma importe impuesto: ' || SumaImpuesto);
        dbms_output.put_line('El impuesto total: ' || ImpuestoTotal);
        IF (SumaImpuesto = ImpuestoTotal) THEN
            dbms_output.put_line('SI coinciden');
        ELSE
            dbms_output.put_line('NO coinciden');
        END IF;
    END LOOP;
END;
/

2. 用聚合函数+NVL避免异常

对于单值查询(比如SELECT SUBTOTAL INTO...),用MAX()或MIN()包裹字段,无匹配记录时返回NULL,再用NVL()转成默认值;SUM函数无数据时返回NULL,同样用NVL处理。这种方式不用写大量异常块,代码更简洁:

DECLARE
    current_id       Comprobante.customertrxid%TYPE;
    SumaImporteCon   NUMBER;
    Subtotal         NUMBER;
    SumaTasa03       NUMBER;
    ImporteTotal03   NUMBER;
    SumaTasa16       NUMBER;
    ImporteTotal16   NUMBER;
    SumaImpuesto     NUMBER;
    ImpuestoTotal    NUMBER;
BEGIN
    FOR id_rec IN (SELECT customertrxid FROM comprobante) LOOP
        current_id := id_rec.customertrxid;
        DBMS_OUTPUT.PUT_LINE('ID: ' || current_id);
        
        -- 用NVL处理SUM的NULL值,用MAX处理单值查询的无数据情况
        SELECT NVL(sum(IMPORTE), 0) INTO SumaImporteCon 
        FROM Conceptos 
        WHERE customertrxid = current_id;
        
        SELECT NVL(MAX(SUBTOTAL), 0) INTO Subtotal 
        FROM Comprobante 
        WHERE customertrxid = current_id;
        
        SELECT NVL(sum(IMPORTE), 0) INTO SumaTasa03 
        FROM Traslados 
        WHERE TasaOcuota = '0.030000' AND customertrxid = current_id;
        
        SELECT NVL(MAX(IMPORTE), 0) INTO ImporteTotal03 
        FROM TrasladosTotal 
        WHERE TasaOcuota = '0.030000' AND customertrxid = current_id;
        
        SELECT NVL(sum(IMPORTE), 0) INTO SumaTasa16 
        FROM Traslados 
        WHERE TasaOcuota = '0.160000' AND customertrxid = current_id;
        
        SELECT NVL(MAX(IMPORTE), 0) INTO ImporteTotal16 
        FROM TrasladosTotal 
        WHERE TasaOcuota = '0.160000' AND customertrxid = current_id;
        
        SELECT NVL(sum(IMPORTE), 0) INTO SumaImpuesto 
        FROM TrasladosTotal 
        WHERE customertrxid = current_id;
        
        SELECT NVL(MAX(TOTALIMPUESTOSTRASLADOS), 0) INTO ImpuestoTotal 
        FROM ImpuestosTotal 
        WHERE customertrxid = current_id;
        
        -- 输出对比结果(同原代码)
        dbms_output.put_line('Suma importe conceptos ' || SumaImporteCon);
        dbms_output.put_line('Subtotal Comprobante: ' || Subtotal);
        IF (SumaImporteCon = Subtotal) THEN
            dbms_output.put_line('SI coinciden');
        ELSE
            dbms_output.put_line('NO coinciden');
        END IF;
        
        -- 后续输出逻辑同原代码,此处省略
    END LOOP;
END;
/

3. 合并查询(推荐)

把多个表的查询合并成一个,用LEFT JOIN关联所有表,一次性获取所有需要的数据,既避免了多次SELECT INTO的异常问题,还能提升执行效率:

DECLARE
    CURSOR c_data IS
        SELECT 
            c.customertrxid,
            NVL(sum_con.SumaImporteCon, 0) AS SumaImporteCon,
            NVL(cp.Subtotal, 0) AS Subtotal,
            NVL(sum_t03.SumaTasa03, 0) AS SumaTasa03,
            NVL(tt03.ImporteTotal03, 0) AS ImporteTotal03,
            NVL(sum_t16.SumaTasa16, 0) AS SumaTasa16,
            NVL(tt16.ImporteTotal16, 0) AS ImporteTotal16,
            NVL(sum_tt.SumaImpuesto, 0) AS SumaImpuesto,
            NVL(it.ImpuestoTotal, 0) AS ImpuestoTotal
        FROM comprobante c
        LEFT JOIN (
            SELECT customertrxid, sum(IMPORTE) AS SumaImporteCon
            FROM Conceptos
            GROUP BY customertrxid
        ) sum_con ON c.customertrxid = sum_con.customertrxid
        LEFT JOIN (
            SELECT customertrxid, SUBTOTAL
            FROM Comprobante
        ) cp ON c.customertrxid = cp.customertrxid
        LEFT JOIN (
            SELECT customertrxid, sum(IMPORTE) AS SumaTasa03
            FROM Traslados
            WHERE TasaOcuota = '0.030000'
            GROUP BY customertrxid
        ) sum_t03 ON c.customertrxid = sum_t03.customertrxid
        LEFT JOIN (
            SELECT customertrxid, IMPORTE AS ImporteTotal03
            FROM TrasladosTotal
            WHERE TasaOcuota = '0.030000'
        ) tt03 ON c.customertrxid = tt03.customertrxid
        LEFT JOIN (
            SELECT customertrxid, sum(IMPORTE) AS SumaTasa16
            FROM Traslados
            WHERE TasaOcuota = '0.160000'
            GROUP BY customertrxid
        ) sum_t16 ON c.customertrxid = sum_t16.customertrxid
        LEFT JOIN (
            SELECT customertrxid, IMPORTE AS ImporteTotal16
            FROM TrasladosTotal
            WHERE TasaOcuota = '0.160000'
        ) tt16 ON c.customertrxid = tt16.customertrxid
        LEFT JOIN (
            SELECT customertrxid, sum(IMPORTE) AS SumaImpuesto
            FROM TrasladosTotal
            GROUP BY customertrxid
        ) sum_tt ON c.customertrxid = sum_tt.customertrxid
        LEFT JOIN (
            SELECT customertrxid, TOTALIMPUESTOSTRASLADOS AS ImpuestoTotal
            FROM ImpuestosTotal
        ) it ON c.customertrxid = it.customertrxid;
    r_data c_data%ROWTYPE;
BEGIN
    FOR r_data IN c_data LOOP
        DBMS_OUTPUT.PUT_LINE('ID: ' || r_data.customertrxid);
        
        dbms_output.put_line('Suma importe conceptos ' || r_data.SumaImporteCon);
        dbms_output.put_line('Subtotal Comprobante: ' || r_data.Subtotal);
        IF (r_data.SumaImporteCon = r_data.Subtotal) THEN
            dbms_output.put_line('SI coinciden');
        ELSE
            dbms_output.put_line('NO coinciden');
        END IF;
        
        dbms_output.put_line('Suma tasa 0.03: ' || r_data.SumaTasa03);
        dbms_output.put_line('Importe 0.03: ' || r_data.ImporteTotal03);
        IF (r_data.SumaTasa03 = r_data.ImporteTotal03) THEN
            dbms_output.put_line('SI coinciden');
        ELSE
            dbms_output.put_line('NO coinciden');
        END IF;
        
        dbms_output.put_line('Suma tasa 0.16: ' || r_data.SumaTasa16);
        dbms_output.put_line('Importe 0.16: ' || r_data.ImporteTotal16);
        IF (r_data.SumaTasa16 = r_data.ImporteTotal16) THEN
            dbms_output.put_line('SI coinciden');
        ELSE
            dbms_output.put_line('NO coinciden');
        END IF;
        
        dbms_output.put_line('Suma importe impuesto: ' || r_data.SumaImpuesto);
        dbms_output.put_line('El impuesto total: ' || r_data.ImpuestoTotal);
        IF (r_data.SumaImpuesto = r_data.ImpuestoTotal) THEN
            dbms_output.put_line('SI coinciden');
        ELSE
            dbms_output.put_line('NO coinciden');
        END IF;
    END LOOP;
END;
/

这种方式把多次单表查询改成一次关联查询,减少了数据库交互次数,性能更好;同时LEFT JOIN保证即使某个表没有对应数据,也能返回NULL,再用NVL转成默认值,完全避免NO_DATA_FOUND异常。


内容的提问来源于stack exchange,提问作者AXEL EDUARDO ESCOBEDO FIGUEROA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:14:57