【问题标题】:Create record from refcursor从 refcursor 创建记录
【发布时间】:2020-05-07 23:48:31
【问题描述】:

我想从 refcursor 创建记录。我的代码:

set serveroutput on    
DECLARE
  c_curs    SYS_REFCURSOR;
  v_id      NUMBER;
BEGIN

  pck_prov.get_value_type_list (1, c_curs); --> procedure called here
  -- I guess this is the place where record can be created from cursor.

  LOOP 
    FETCH c_curs
    INTO  v_id;--instead of fetching into variable I would like to fetch into row
    EXIT WHEN c_curs%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(v_id);--if fetching is done into row, only selected columns can be printed, like myrow.id
  END LOOP;
  CLOSE c_curs;
END;

请注意:我知道如何从使用 select 语句定义的游标创建记录,如 here 所述。我不知道如何对 refcursors 使用相同的技术。

编辑:

来自here 的代码正是我所需要的,但它会引发错误:

set serveroutput on
VAR c_curs refcursor;

EXECUTE pck_prov.get_value_type_list(1, :c_curs);


BEGIN
    FOR record_test IN :c_curs LOOP
        dbms_output.put_line(record_test.id);
    END LOOP;
END;

错误:错误 PLS-00456:项目 'SQLDEVBIND1Z_1' 不是游标。

只是为了澄清问题:

在我的数据库中大约有 200 个包。 每个包内部都有几个存储过程 - 通常每个过程都与来自不同表的列组合在一起。这就是为什么最好有一些动态创建的光标,这样我就可以像我发布的示例一样进行简单的选择。

【问题讨论】:

  • 我认为您在这里对变量和行有误。该变量将仅保存游标单列的单个值。因此,如果您的光标返回 3 列,那么您需要声明 3 个变量INTO v_id, name, dept。那你提的和DBMS_OUTPUT.PUT_LINE(v_id || ', ' || name || ', ' || dept)一样@
  • @LalitKumarB - 是的,我明白这一点。我的问题是我有存储过程,它从不同的表中返回超过 50 列。我只需要展示其中的一些。这就是为什么提取从游标创建的行会容易得多。
  • 这可能取决于您想要记录的内容。 PL/SQL 记录不能有直到运行时才知道的定义,但可以有 XML、JSON、CSV 等。

标签: oracle plsql


【解决方案1】:

从 Oracle 12.1 开始,您可以使用 DBMS_SQL.return_result 过程。 SQL Plus 自动显示隐式语句结果的内容。因此,DBMS_SQL 包中的RETURN_RESULT 过程允许您隐式传递它们,而不是定义显式引用游标参数。

DECLARE
  c_curs    SYS_REFCURSOR;
  v_id      NUMBER;
BEGIN

  pck_prov.get_value_type_list (1, c_curs);

  DBMS_SQL.return_result(c_curs); --> Passes ref cursor output implicitly
END;
/

事实上,不需要这个单独的 PL/SQL 块,您可以在原来的 pck_prov.get_value_type_list 过程本身中添加 DBMS_SQL.return_result(c_curs) 语句。

【讨论】:

  • 谢谢你,我不知道。是否可以以某种方式循环结果并打印所需的列?
  • 是的,您可以手动完成。我的回答会自动为您做到这一点。要循环显示,你可以做类似DBMS_OUTPUT.PUT_LINE(v_id || ', ' || name || ', ' || dept) 之类的事情。
  • 在此处查看示例oracle-base.com/articles/misc/…
【解决方案2】:

只需定义一个与游标匹配的 PL/SQL RECORD 类型并将 FETCH 放入其中。

DECLARE
  c_curs    SYS_REFCURSOR;
  TYPE rec_t IS RECORD ( object_name VARCHAR2(30), object_type VARCHAR2(30) );
  v_rec     rec_t;
BEGIN

  OPEN c_curs FOR 
       SELECT object_name, 
              object_type 
       FROM   dba_objects 
       WHERE  object_name like 'DBA%TAB%';  

  LOOP 
    FETCH c_curs
    INTO  v_rec;
    EXIT WHEN c_curs%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(v_rec.object_name || ' - ' || v_rec.object_type);
  END LOOP;
  CLOSE c_curs;
END;
DBA_ADVISOR_SQLA_TABLES - VIEW
DBA_ADVISOR_SQLA_TABVOL - VIEW
DBA_ADVISOR_SQLW_TABLES - VIEW
DBA_ADVISOR_SQLW_TABVOL - VIEW
DBA_ALL_TABLES - VIEW
etc...

【讨论】:

  • 但是没有其他方法不需要显式定义记录?我问这个是因为我有大约 50 列(在一个示例中,有几个示例需要这个),而我以后通常只需要显示其中的几个列。
  • 您可以为 select 语句声明游标,然后将 v_rec 设为 c_curs%ROWTYPE 类型
  • 但我的选择是来自包内的存储过程。
  • 在该包的包规范中定义光标。这将使其公开可见。
  • 有这方面的例子吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多