2

我有一个程序可以让我得到带有 refcursor 的输出,并且光标中的数据/结构将是动态的。每次取决于输入数据类型,游标中的列数会有所不同。那么我怎样才能访问这个结构并获取数据类型呢?

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;**
4

2 回答 2

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
于 2017-03-02T19:32:23.457 回答
2

由于您使用的是 11g,因此您可以使用dbms_sql来询问您的引用光标,然后遍历列类型。它们被报告为数字,因此您需要将类型数字转换为字符串(在此处列出)。

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

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_.

于 2017-03-02T19:31:16.917 回答