4

在 PL/SQL 中,我可以在这里使用类似这样的技巧来从 a 中找出一行中每一列的名称/值对REF CURSOR

Oracle PL/SQL TABLE 类型的 TO_CHAR

这是一个很棒的技巧。但是当为空时它不起作用REF CURSOR,例如这里的这个(这只是一个例子。真正的光标不选择 from DUAL):

OPEN cursor FOR SELECT 1 FROM DUAL WHERE 1 = 0;

空的REF CURSOR甚至有列名/类型信息吗?

4

2 回答 2

2

AFAIK,没有办法REF CURSOR直接从 PL/SQL 获取元数据。奇怪的是, aREF CURSOR映射到 Java 的ResultSet,可以查询调用其ResultSet.getMetaData方法的元数据。

所以你可以生成一个 Java 的存储过程来为你做这件事。在这里你可以找到一个例子。

另一个选项是使用(仅在 11g 中)将游标转换为数字游标,可以使用DBMS_SQLDBMS_SQL.TO_CURSOR_NUMBER询问元数据。

于 2011-07-01T08:11:35.050 回答
2

是的,我已经尝试过没有行的解决方案,你是对的。从我有限的角度来看,我认为这里我们需要两种不同的方法来检索列的名称和值。

1) Dbms_sql 包来检索列的名称。

2) tbone方法来检索数据。


程序

create or replace procedure demo(sqlText in varchar2) is
    refCur sys_refcursor;
    curId  integer;
    cnt    number;
    ret    dbms_sql.desc_tab;
    recTab dbms_sql.desc_tab;
    FORMAT_STRING constant pls_integer := 20;

    procedure printDescTab(desctab in sys.dbms_sql.desc_tab) is
    begin
        -- do what you want with the columns
        for i in 1 .. desctab.count
        loop
            dbms_output.put(lpad(desctab(i).col_name, FORMAT_STRING));
        end loop;
        dbms_output.new_line;
    end printDescTab;

    procedure PrintCur(cv in sys_refcursor) is
    begin
        for c in ( --select t2.COLUMN_VALUE.getrootelement() name,
                  select EXTRACTVALUE(t2.COLUMN_VALUE, 'node()') value
                  from   table(XMLSEQUENCE(cv)) t
                         ,table(XMLSEQUENCE(EXTRACT(COLUMN_VALUE, '/ROW/node()'))) t2)
        loop
            DBMS_OUTPUT.put(lpad(c.VALUE, FORMAT_STRING));
        end loop;
        dbms_output.new_line;
        dbms_output.new_line;
    end;

begin
    dbms_output.put_line('dynamic sql: ' || sqlText);
    curId := dbms_sql.open_cursor();
    --  checks for sql injection to do...
    dbms_sql.parse(curId, sqlText, dbms_sql.native);
    dbms_sql.describe_columns(curId, cnt, recTab);
    printDescTab(recTab);
    dbms_sql.close_cursor(curId);

    open refCur for sqlText;
    PrintCur(refCur);
    close refCur;
exception
    when others then
        if dbms_sql.is_open(curId) then
           dbms_sql.close_cursor(curId);
        end if;
        if refCur%isopen then
            close RefCur;
        end if;
        dbms_output.put_line(sqlcode || ' - ' || sqlerrm);
end demo;

测试

declare
    sqlText varchar2(2000);
begin
    sqlText := 'select 1 as one, 2 as two  from  dual where 1=0';
    demo(sqlText);
    sqlText   := 'select name, type || chr(13) type' -- chr(13) specific ASCII Carriage return
                ||' from   user_plsql_object_settings'
                ||' where name not like ''%$%'' and  rownum <= 10';      
    demo(sqlText);   
    sqlText := 'select 1 as one, 2 as two  from  dual ';                  
    demo(sqlText);

exception
    when others then
        dbms_output.put_line(sqlcode || ' - ' || sqlerrm);
end;

结果

dynamic sql: select 1 as one, 2 as two  from  dual where 1=0
                 ONE                 TWO


dynamic sql: select name, type || chr(13) type from   user_plsql_object_settings where name not like '%$%' and  rownum <= 10
                NAME                TYPE
     ADD_JOB_HISTORY          PROCEDURE
    AFT_INS_TEST_TRG            TRIGGER
    BEF_DEL_TEST_TRG            TRIGGER
    BEF_INS_TEST_TRG            TRIGGER
            BETWNSTR           FUNCTION
                BOOL           FUNCTION
    CACHED_FIBONACCI           FUNCTION
               DEBUG            PACKAGE
               DEBUG       PACKAGE BODY
          DEBUG_TEST          PROCEDURE


dynamic sql: select 1 as one, 2 as two  from  dual 
                 ONE                 TWO
                   1                   2
于 2011-07-01T18:36:56.393 回答