PLSQL IMPLICIT CURSOR 在 CURSOR 之后没有找到数据

Posted

技术标签:

【中文标题】PLSQL IMPLICIT CURSOR 在 CURSOR 之后没有找到数据【英文标题】:PLSQL IMPLICIT CURSOR No Data Found After CURSOR 【发布时间】:2018-04-22 13:30:20 【问题描述】:

我有一个运行良好的主光标。

declare

    v_firm_id number;
    amount number;
    v_total_sum TABLE_TEMP.TOTAL_SUM%TYPE;

    CURSOR MT_CURSOR IS
        SELECT firm_id FROM t_firm;

BEGIN
    OPEN MT_CURSOR;
    LOOP
        FETCH MT_CURSOR INTO v_firm_id;
        EXIT WHEN MT_CURSOR%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(to_char(sysdate, 'mi:ss')  ||'--- '|| v_firm_id)
        INSERT INTO TABLE_TEMP(TOTAL_SUM) VALUES(v_firm_id) 
        COMMIT;
    END LOOP;

    DBMS_LOCK.SLEEP(20);

    BEGIN
        FOR loop_emp IN
            (SELECT TOTAL_SUM INTO v_total_sum FROM TABLE_TEMP)
        LOOP
            dbms_output.put_line(to_char(sysdate, 'mi:ss')  ||'--- '|| v_total_sum || '-TEST--');
        END LOOP loop_emp;
    END;
end;

除了dbms_output.put_line(v_total_sum || '---');之外一切正常

我在那里没有得到任何数据。我得到正确的行数。它插入的。

【问题讨论】:

TABLE_TEMP 是全局临时表吗?如果是,它的保留设置是什么? 标准问题 - dbms_output 是否启用?你能通过调试器运行它,看看它在做什么吗?此外,问题标题显示“未找到数据” - 这与 dbms_output 问题有何关系?数据是否存在于表的末尾? @APC TABLE_TEMP 是我在运行此过程之前已经创建的实际表。 那么,它的保留设置是什么? @WilliamRobertson 是的,它已启用,因为我已经在相同的代码中通过执行 ` DBMS_OUTPUT.PUT_LINE(to_char(sysdate, 'mi:ss') ||'--- '|| v_firm_id 对其进行了测试)` 【参考方案1】:

问题是游标 FOR 循环有一个多余的 into 子句,编译器会默默地忽略它,因此永远不会使用 v_total_sum

试试这个:

begin
    for r in (
        select firm_id from t_firm
    )
    loop
        insert into table_temp (total_sum) values (r.firm_id);
    end loop;

    dbms_lock.sleep(20);

    for r in (
        select total_sum from table_temp
    )
    loop
        dbms_output.put_line(r.total_sum || '---');
    end loop;

    commit;
end;

如果这是一个存储过程而不是匿名块,并且您使用 alter session set plsql_warnings = 'ENABLE:ALL';(或 IDE 中的等效首选项设置)启用了 PL/SQL 编译器警告,那么您会看到:

PLW-05016: INTO clause should not be specified here

我还将commit 移到了末尾,因此您只需提交一次。

总结下面的 cmets,Cursor FOR 循环构造为您声明、打开、获取和关闭游标,并且可能更快,因为它以 100 个为单位进行获取(或类似的 - 我在最近的版本中没有测试过) .更简单的代码出现错误的可能性更小,并且将来更易于维护,例如,如果您需要在光标上添加一列。

注意原来的版本有:

for loop_emp in (...)
loop
    ...
end loop loop_emp;

这是一种误导,因为loop_emp记录 的名称,而不是光标或循环的名称。编译器忽略了end loop 之后的文本,尽管它至少应该警告你。如果要命名循环,可以在其上方使用label like <<LOOP_EMP>>。 (我总是将我的循环记录命名为r,类似于您经常在数字循环中看到的i。)

【讨论】:

所以我不需要CURSOR? 当您可以使用 Cursor FOR 循环构造时,您不需要显式声明它。这将为您声明、打开、获取和关闭游标。 威廉,我用你的代码修改了我的代码。我使用了loop_emp.total_sum,它开始工作了。我得到了我期待的输出。你有什么理由不使用它吗?更改我的整个代码需要做很多工作。我只发布了整个代码的一小部分。 @user206168 - 一致性是代码的优点。当您在一个循环中使用显式游标而在第二个循环中使用隐式游标时,您的同事会想知道为什么。当然,您的代码只需从第二个游标循环中删除 INTO v_total_sum 即可。但是你的理解比它需要的更难。 越简单越好 - 出现错误的机会越少,将来也更容易维护。此外,Cursor FOR 循环会自动批量获取 100 个,因此对于大量行可能更有效(尽管在这种情况下您可能不会使用循环)。

以上是关于PLSQL IMPLICIT CURSOR 在 CURSOR 之后没有找到数据的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework 5.0.0 Function Import 以及 Implicit REF CURSOR Binding

plsql cursor 函数

PLSQL中显示Cursor隐示Cursor动态Ref Cursor差别

PLSQL中显示Cursor隐示Cursor动态Ref Cursor差别

执行 CURSOR 时的 PLSQL FOR 循环

Oracle/PLSQL CURSOR FOR Loop