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

Posted

技术标签:

【中文标题】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 在变量中存储具有未知数据类型的游标(使用 FETCH INTO)的主要内容,如果未能解决你的问题,请参考以下文章

存储过程

Oracle存储过程游标for循环怎么写

plsql--游标用法

Oracle数据库存储过程中输出参数为自定义游标类型时,使用call或者exec调用时,用啥来给游标赋值

REF CURSOR 总结

Oracle-4 - :超级适合初学者的入门级笔记:plsql,基本语法,记录类型,循环,游标,异常处理,存储过程,存储函数,触发器