PLSQL中怎样获取未知结构的动态游标的字段名

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PLSQL中怎样获取未知结构的动态游标的字段名相关的知识,希望对你有一定的参考价值。

参考技术A 如果给的是一个查询SQL文本,那么事情很容易(对于9i及以上版本),只要使用dbms_sql.open_cursor打开游标,再使用dbms_sql.describe_columns即可得到游标的所有字段名称及类型等数据,存储在一个集合类型变量中(具体请看dbms_sql.desc_tab)。请参考如下PLSQL代码:
DECLARE
l_curidINTEGER; l_cntNUMBER;
l_desctabdbms_sql.desc_tab; l_sqltextVARCHAR2(2000); BEGIN
l_sqltext := 'select owner,object_type,object_name from dba_objects
where rownum<= 10';--可以是任意有效的查询sql文本 l_curid := dbms_sql.open_cursor();
dbms_sql.parse(l_curid, l_sqltext, dbms_sql.native); dbms_sql.describe_columns(l_curid, l_cnt, l_descTab);
FOR i IN1 ..l_desctab.count LOOP
dbms_output.put(lpad(l_desctab(i).col_name, 20)); ENDLOOP;
dbms_output.new_line;
dbms_sql.close_cursor(l_curId); END;
运行结果如下:
OWNER OBJECT_TYPE OBJECT_NAME
注意,必须使用 DBMS_SQL.OPEN_CURSOR 打开游标,否则,就不是这种处理方法了。本回答被提问者和网友采纳

PLSQL 在变量中存储具有未知数据类型的游标(使用 FETCH INTO)

【中文标题】PLSQL 在变量中存储具有未知数据类型的游标(使用 FETCH INTO)【英文标题】:PLSQL Store cursor with unknown data type in a variable (using FETCH INTO) 【发布时间】:2017-11-13 04:50:54 【问题描述】:

我是 PLSQL 的新手,并尝试完成以下任务:遍历用户架构中的所有列并为每列输出唯一值。 我正在尝试使用嵌套游标,初始游标是每列,嵌套游标是每列的唯一值。我遇到的问题似乎是嵌套游标具有各种类型的值(取决于列)并且无法放入定义为 varchar2 的变量中。 This question 建议这应该可以工作,并且日期和数字变量将被隐式转换为字符。但是,我似乎无法让它工作,我的代码产生了以下错误:

ORA-06502:PL/SQL:数字或值错误。

我曾尝试(未成功)通过使用 to_char() 将光标强制为字符变量: 'FETCH TO_CHAR(row_cursor) INTO...' 这也不起作用。

有没有办法存储未知类型的数据以便输出?有没有更好的方法来列出架构中所有列的唯一值?

编辑:根据@Kaushik-Nayak 的评论,我深入研究了一些正在处理的列/表。一些内部 Oracle 视图似乎有已弃用的类型(我开始看到很多 ORA-00932: inconsistent datatypes: expected CHAR got LONG)错误(导致我发现 this question)。为了解决这个问题,我为我想要分析的所有表添加了一个公共前缀(在本例中为“MY_”),并添加了一个 WHERE 子句,并在 SUBSTR() 函数的帮助下仅从具有公共前缀的表中获取列来自user_tab_columns 表。此更改解决了问题:

DECLARE
  row_cursor SYS_REFCURSOR;
  var_rowval VARCHAR2(4000);

BEGIN
  FOR c IN (SELECT table_name, column_name FROM user_tab_columns WHERE SUBSTR(table_name, 1, 2) = 'MY') 
  LOOP

这是我的(原始)代码:

DECLARE
  row_cursor SYS_REFCURSOR;
  var_rowval VARCHAR2(500);

BEGIN
  FOR c IN (SELECT table_name, column_name FROM user_tab_columns) 
  LOOP
      OPEN row_cursor
        FOR 'SELECT DISTINCT ' || c.column_name || ' FROM ' || c.table_name;
          LOOP
            FETCH row_cursor INTO var_rowval;
            dbms_output.put_line(c.table_name || ', ' || c.column_name || ': ' || var_rowval );
            EXIT WHEN row_cursor%NOTFOUND;
          END LOOP;
      CLOSE row_cursor;
  END LOOP;      
END;

【问题讨论】:

问题不在于数据类型,而在于大小。您可能有一个值大于 500 的列。您必须保持 var_rowval 的大小足够大(可能是 4000)以容纳所有类型的列。但是,如果您有 CLOB 列,您可能仍然会遇到问题。因此,最好重新设计代码以避免此类错误。 与问题无关,但您不能以您使用的方式使用SYS_REFCURSOR。首先纠正它。 【参考方案1】:

我在我的架构上运行了你的代码,它运行良好,没有任何错误。我的表有数据类型 varchar2NumberDate 的列。正如所言 @Kaushik Nayak 请将变量“var_rowval(500)”的大小增加到 “var_rowval(4000)”。

还有一个建议,请不要对所有表运行此代码,因为当您使用 dbms_output.put_line() 打印它时,您会得到 缓冲区溢出错误。为了便于理解,您可以占用 2 到 3 个表并尝试打印这些列的不同值。

您想找到导致问题的列,下面是可以帮助您实现该目标的代码。

    set serveroutput on      
DECLARE
  row_cursor SYS_REFCURSOR;
  var_rowval VARCHAR2(500);

BEGIN
  FOR c IN (SELECT * /*table_name, column_name*/ FROM user_tab_columns) 
  LOOP
  begin
  OPEN row_cursor
        FOR 'SELECT DISTINCT ' || c.column_name || ' FROM ' || c.table_name;
          LOOP

            FETCH row_cursor INTO var_rowval;
            dbms_output.put_line(c.table_name || ', ' || c.column_name || ': ' || var_rowval );
            EXIT WHEN row_cursor%NOTFOUND;
          END LOOP;
      CLOSE row_cursor;
           exception
            when others then 
           dbms_output.put_line('Table Name:'||' '||c.table_name||' '||'column name'||c.column_name||','||'data type:'||' '||c.data_type);
            EXIT;
            end;  

  END LOOP;      
END;
/

【讨论】:

以上是关于PLSQL中怎样获取未知结构的动态游标的字段名的主要内容,如果未能解决你的问题,请参考以下文章

游标 PLSQL 中的动态列名

在plsql中使用游标更新多条记录

PLSQL - 游标不能在动态 sql 中使用

在 Oracle PLSQL 中使用游标的动态列名

从 PLSQL 中所有动态找到的表中获取数据时遇到问题

提高插入游标的性能?