将显式游标转换为引用游标而不重命名列ATTR_n

时间:2017-12-22 19:42:43

标签: oracle plsql

我希望在游标上运行一些代码,但也要报告游标的内容,以便我可以预览它将要执行的操作。预览是Excel中的查询表,并希望REF CURSOR语法为{Call}。在PL / SQL中,编码的自然语法是显式游标。在this question的@XING的帮助下,我开发了这个软件包。

CREATE OR REPLACE PACKAGE MyPackage
AS

  -- This could be a complex query with many paramters and columns
  CURSOR curMyCursor(pParam1 VARCHAR2) IS
  SELECT pParam1 hello, 'ColNames' goodbye
  FROM DUAL;

  -- I could just let GiveMyCursor return a SYS_REFCURSOR but wanted to try max clues
  TYPE refMyCursor IS REF CURSOR RETURN curMyCursor%ROWTYPE;
  -- The TABLE function in GiveMyCursor needs the row type to be externalized
  TYPE typMyCursor IS TABLE OF curMyCursor%ROWTYPE;

  PROCEDURE RunMyCursor(pParam1 IN VARCHAR2);
  PROCEDURE GiveMyCursor(pCursor OUT refMyCursor, pParam1 IN VARCHAR2);

END MyPackage;
/

CREATE OR REPLACE PACKAGE BODY MyPackage
AS

  PROCEDURE RunMyCursor(pParam1 IN VARCHAR2) IS
  BEGIN
    FOR recMyCursor IN curMyCursor(pParam1) LOOP
      NULL; -- Do normal cursor loop processing
    END LOOP;
  END RunMyCursor;

  PROCEDURE GiveMyCursor(pCursor OUT refMyCursor, pParam1 IN VARCHAR2) IS
    tabMyCursor typMyCursor;
  BEGIN
    OPEN curMyCursor(pParam1);
    -- Load the entire contents of the cursor into memory and pray it fits
    FETCH curMyCursor BULK COLLECT INTO tabMyCursor;  
    CLOSE curMyCursor;

    -- PROBLEM: The TABLE function renames the columns ATTR_1, ATTR_2, etc
    OPEN pCursor FOR 
    SELECT ATTR_1 HELLO, ATTR_2 GOODBYE 
    FROM TABLE(tabMyCursor);
  END GiveMyCursor;

END MyPackage;
/

对于我的预览,我想给最终用户一个简单的表,过滤他们可以刷新的排序。在不重复查询的情况下,使用一个简单的Excel查询表,其中包含一个返回REF CURSOR的过程。 {call MyPackage.GiveMyCursor('World')}给出:

HELLO | GOODBYE
------+---------
World | ColNames

如果我没有在OPEN pCursor中重新指定列名,那么

ATTR_1| ATTR_2
------+---------
World | ColNames

所以OPEN pCursor FOR SELECT *允许我增强/修复我的查询而不会产生其他维护后果,但最终用户会丢失列描述。

在GiveMyCursor中是否有某种方法我可以添加一些代码以防止必须重新指定所有列名。一些内置的DBMS包我可以对游标或其中一种类型进行整理以构建一个字符串或某些内容以使其保持通用?

我的数据库是Oracle 12.1.0.1 SE。

1 个答案:

答案 0 :(得分:2)

我不清楚为什么当REF CURSOR本身可以通过时,您需要第二个OUT作为curMyCursor参数。

在您的代码评论中,

  

- 将光标的全部内容加载到内存中并祈祷它适合

你可能认为将记录存储在内存中会产生更好的性能吗?事实上,当您使用CURSOR时,Oracle实际上会打开一个存储处理信息的未命名工作区。那么,为什么不直接传递第一个CURSOR并在调用块中使用它?

在你的情况下说了这句话

FETCH curMyCursor BULK COLLECT INTO tabMyCursor

不进行列到列的映射,除非您在声明集合时已正确定义它。

您可以做的是,使用预期的列数据类型声明RECORD

 TYPE MyrecordType is RECORD 
(
 hello VARCHAR2(10),
 goodbye VARCHAR2(10)
 );
TYPE typMyCursor IS TABLE OF MyrecordType ;

而不是

TYPE typMyCursor IS TABLE OF curMyCursor%ROWTYPE;

现在,您将拥有集合中记录元素的所有列的专有名称。然后,您应该能够直接使用SELECT *而不是指定元素。

OPEN pCursor FOR 
    SELECT *
    FROM TABLE(tabMyCursor);