How to access the structure and get the column list ,datatypes of refcursor?

前端 未结 2 1147
既然无缘
既然无缘 2020-12-17 06:21

I have a procedure which gets me the output with refcursor and data/structure in cursor will be dynami. Each time depending on inputs datatypes and no of columns in cursor w

相关标签:
2条回答
  • Since you're on 11g, you can use the dbms_sql package to interrogate your ref cursor, and then loop over the column types. They are reported as numbers so you'll need to translate the type numbers to strings (listed here).

    This is a demo to give you the idea:

    set serveroutput on
    DECLARE
      -- mimicking your procedure arguments
      wrapper_ SYS_REFCURSOR;
      datyapes_ VARCHAR(100);
    
      L_COLS NUMBER;
      L_DESC DBMS_SQL.DESC_TAB;
      L_CURS INTEGER;
      L_VARCHAR VARCHAR2(4000);
    BEGIN
      -- fake cursor, instead of procedure call
      open wrapper_ for q'[select 42, 'Test', date '2017-03-02' from dual]';
    
      L_CURS := DBMS_SQL.TO_CURSOR_NUMBER(wrapper_);
      DBMS_SQL.DESCRIBE_COLUMNS(C => L_CURS, COL_CNT => L_COLS,
        DESC_T => L_DESC);
    
      FOR i IN 1..L_COLS LOOP
        datyapes_ := datyapes_ || CASE WHEN i > 1 THEN '|' END
          || CASE L_DESC(i).col_type
            WHEN 1 THEN 'VARCHAR2'
            WHEN 2 THEN 'NUMBER'
            WHEN 12 THEN 'DATE'
            WHEN 96 THEN 'CHAR'
            WHEN 180 THEN 'TS'
            -- more types as needed
            ELSE 'unknown'
          END;
      END LOOP;
    
      DBMS_SQL.CLOSE_CURSOR(L_CURS);
    
      -- just for debug
      dbms_output.put_line('datyapes_: ' || datyapes_);
    END;
    /
    

    which gets output:

    datyapes_: NUMBER|CHAR|DATE
    
    PL/SQL procedure successfully completed.
    

    I've kept your variable name as datyapes_ as shown in the question, but perhaps you really have datatypes_.

    0 讨论(0)
  • 2020-12-17 07:11

    You can convert the ref cursor to a DBMS_SQL cursor using the DBMS_SQL.TO_CURSOR_NUMBER function. Then, having the cursor number, you can inspect manipulate it via DBMS_SQL. This includes being able to describe it's columns, as shown in the example below:

    DECLARE
      l_rc              SYS_REFCURSOR;
    
      l_cursor_number   INTEGER;
      l_col_cnt         INTEGER;
      l_desc_tab        DBMS_SQL.desc_tab;
      l_col_num         INTEGER;
    BEGIN
      OPEN l_rc FOR 'SELECT object_name, object_type, last_ddl_time FROM dba_objects where rownum <= 10';
    
      l_cursor_number   := DBMS_SQL.to_cursor_number (l_rc);
    
      DBMS_SQL.describe_columns (l_cursor_number, l_col_cnt, l_desc_tab);
    
      l_col_num         := l_desc_tab.FIRST;
    
      IF (l_col_num IS NOT NULL) THEN
        LOOP
          DBMS_OUTPUT.put_line ('Column #' || l_col_num);
          DBMS_OUTPUT.put_line ('...name: ' || l_desc_tab (l_col_num).col_name);
          DBMS_OUTPUT.put_line ('...type: ' || l_desc_tab (l_col_num).col_type);
          DBMS_OUTPUT.put_line ('...maxlen: ' || l_desc_tab (l_col_num).col_max_len);
          -- ... other fields available in l_desc_tab(l_col_num) too.
          l_col_num   := l_desc_tab.NEXT (l_col_num);
          EXIT WHEN (l_col_num IS NULL);
        END LOOP;
      END IF;
    
      DBMS_SQL.close_cursor (l_cursor_number);
    END;
    

    Output

    Column #1
    ...name: OBJECT_NAME
    ...type: 1
    ...maxlen: 128
    Column #2
    ...name: OBJECT_TYPE
    ...type: 1
    ...maxlen: 23
    Column #3
    ...name: LAST_DDL_TIME
    ...type: 12
    ...maxlen: 7
    
    0 讨论(0)
提交回复
热议问题