如何访问结构并获取列表,refcursor的数据类型?

时间:2017-03-02 18:26:17

标签: oracle oracle11g cursor sys-refcursor ref-cursor

我有一个过程,它使用refcursor获取输出,并且游标中的数据/结构将是dynami。每次取决于输入数据类型和游标中的列数都不会有所不同。那么如何访问此结构并获取数据类型?

PROCEDURE  PROC_B ( name_     IN       VARCHAR2,
                    date_     IN       DATE,
                    code_           IN       VARCHAR2,
                    sp_name_       IN       VARCHAR2,
                    wrapper_         OUT      sys_refcursor,
                    datyapes_     OUT      VARCHAR2,
                     TS2_     OUT      VARCHAR2,
                     header_   OUT      VARCHAR2)
AS
      TS_         DATE;
BEGIN
      PROC_A (name_, date_, code_, sp_name_, wrapper_, TS_, header_);
      TS2_:= TO_CHAR(TS_, 'MM-DD-YYYY.HH24_MI');

      -- Logic should come here for below requirement 
-- Get the datatypes of variables from wrapper_ (ref cursor datatype) and send them back in datyapes_ . 
 -- Eg1 : If ref cursor returns 2 values with dataytpes VARCHAR2 & Num then o/p should be VARCHAR2|NUMBER , 
 --Eg2 : If ref cursor returns 3 values with dataytpes DATE , TIMESTAMP , VARCHAR2 then o/p should be DATE|TS|VARCHAR2

  END;**

2 个答案:

答案 0 :(得分:5)

您可以使用DBMS_SQL功能将引用光标转换为DBMS_SQL.TO_CURSOR_NUMBER光标。然后,使用光标编号,您可以检查是否通过DBMS_SQL进行操作。这包括能够描述它的列,如下例所示:

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;

输出

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

答案 1 :(得分:2)

由于您使用的是11g,因此可以使用the dbms_sql package来查询引用游标,然后循环遍历列类型。它们被报告为数字,因此您需要将类型编号转换为字符串(listed here)。

这是一个给你这个想法的演示:

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;
/

得到输出:

datyapes_: NUMBER|CHAR|DATE

PL/SQL procedure successfully completed.

我已将您的变量名称保留为datyapes_,如问题中所示,但您可能确实拥有datatypes_