dbms_output.put_line 在存储过程的 Cursor For 循环内不起作用

Posted

技术标签:

【中文标题】dbms_output.put_line 在存储过程的 Cursor For 循环内不起作用【英文标题】:dbms_output.put_line doesn't work inside a Cursor For loop of a stored procedure 【发布时间】:2017-10-31 01:17:32 【问题描述】:

我遇到了一个奇怪的问题,似乎非常特定于存储过程中的 CURSOR FOR 循环。为清楚起见,我在 DBeaver 中使用 Oracle,并尝试遍历表中的所有列并打印出 select 语句的结果。

我无法访问确切的代码,但这在功能上是近似的:

CREATE OR REPLACE PROCEDURE column_null(table_name_in IN VARCHAR2) 
AS
str_query VARCHAR2(1000);
temp_number NUMBER(10);
CURSOR col_cursor IS
SELECT * FROM user_tab_cols 
WHERE table_name = table_name_in;

BEGIN
FOR c_id IN col_cursor
LOOP
  str_query := 'select COUNT(*) FROM ' || table_name_in || 
               ' WHERE ' || c_id.column_name || ' IS NOT NULL';
  EXECUTE IMMEDIATE str_query INTO temp_number;
  DBMS_OUTPUT.PUT_LINE(temp_number);
END LOOP;
END;

现在,奇怪的是,如果我在存储函数之外执行完全相同的代码块(减去额外的 DECLARE 关键字),它会按预期工作。即使我尝试在循环中回显“Hello”,它也会按预期工作,但一旦它变成存储过程,它就会停止工作。我今天已经测试了几个小时,完全困惑;作为参考,我最近才开始熟悉 PL/SQL,所以它的奥秘让我无法理解。

此外,它似乎特定于 CURSOR FOR 循环;如果我用通用数字循环(即FOR c_id IN 1 .. 10)替换 Cursor For 循环,则程序将产生很好的输出。受影响的不仅仅是DBMS_OUTPUT.PUT_LINE;几乎所有在 Cursor For 循环中发生的所有内容都会在存储过程中被忽略,包括变量更新,即使它们在正常的 PL/SQL 块中工作正常。

总结:作为 PL/SQL 块工作正常,在数字 for 循环中工作正常,但由于某种原因,存储过程和游标 for 循环的确切组合导致不产生输出;事实上,从我的测试来看,在存储函数的游标 for 循环中似乎没有发生任何有意义的事情。

这是一个 DBeaver 错误吗? PL/SQL 奇怪?我在这里发帖是因为我不知道这是否是由于过程和/或光标 For 循环的工作方式而导致的预期行为,或者这是否是某种错误。

【问题讨论】:

您将无法打印来自动态 SQL 的数据。并用 REF-CURSOR 处理,然后你就可以得到解决方案。 使用SET SERVEROUTPUT ON 在 SQL 开发人员中工作对我来说很好。 你真的在执行程序吗?如果您编写一个 PLSQL 块并运行它,它会直接显示结果。但是对于程序,您需要在编译后执行该程序。试试exec column_null('Yourtablename'); 我正在使用BEGIN column_null('table_name') END; 调用该过程,这对于其他过程来说效果很好。我相信 Sabarish 的评论可能是正确的,但我需要了解更多关于 REF CURSORS 的信息才能对其进行测试。 【参考方案1】:

你所做的是声明一个过程。现在您已经声明了它,您必须使用如下程序调用它。它很可能会产生输出。

选项 01

    set serveroutput on;
    Declare
      v_table_name_in IN VARCHAR2(499);

    Begin
      v_table_name_in := 'your table name';
      column_null(table_name_in => v_table_name_in);
    end;  

选项 02 获取返回参数。理想情况下,表类型作为输出参数。在上面的代码中,循环遍历它并打印值。

选项 03。 将输出记录到日志表中。

【讨论】:

作为记录,我正在使用 BEGIN column_null('table_name') END; 调用该程序,该程序适用于其他程序。当我了解更多信息时,我会研究选项 2。【参考方案2】:

我发现只需在程序中添加AUTHID current_user 即可解决该错误;显然,该过程无权访问它试图选择的表。奇怪的是,尝试运行该程序时没有产生错误。它只是没有产生任何输出。

【讨论】:

以上是关于dbms_output.put_line 在存储过程的 Cursor For 循环内不起作用的主要内容,如果未能解决你的问题,请参考以下文章

dbms_output.put_line 在存储过程的 Cursor For 循环内不起作用

PL/SQL中测试存储过程,如何立即输出DBMS_OUTPUT的语句。

oracle 10.2.0 如何在plsql 里设置 dbms_output.put_line 打印长度

Oracle PL/SQL 的 dbms_output.put_line() 与 dbms_output.put()

在 dbms_output.put_line 和 dbms_output.put pl/sql 之间混淆

Oracle 中的dbms_output.put_line