ALL_MVIEWS 的循环游标生成 PL/SQL 错误 ORA-06502

Loop cursor of ALL_MVIEWS generate PL/SQL Error ORA-06502

我编写了一个程序来处理将 ALL_MVIEWS 的 QUERY 列的内容写入文件:

DECLARE
  v_out_dir_name VARCHAR2(30) := 'DIR_TEST';
  v_out_dir_path VARCHAR2(60);

  v_count_object_elab NUMBER := 0;

  CURSOR c_mviews IS
    SELECT
        LOWER(MVIEW_NAME) || '.sql' AS FILE_NAME
      , QUERY AS SCRIPT
    FROM ALL_MVIEWS
  ;

  v_file UTL_FILE.file_type;
BEGIN
  FOR r_mview IN c_mviews LOOP
    v_file := UTL_FILE.fopen (v_out_dir_name, r_mview.FILE_NAME, 'w');
    UTL_FILE.putf (v_file, r_mview.SCRIPT);
    UTL_FILE.fclose (v_file);
    v_count_object_elab := v_count_object_elab + 1;
  END LOOP;

  IF v_count_object_elab = 0
  THEN
    DBMS_OUTPUT.PUT_LINE('NESSUN FILE ELABORATO');
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('ERRORE = ' || SQLERRM);

    IF UTL_FILE.IS_OPEN (v_file) THEN
      UTL_FILE.FCLOSE (v_file);
    END IF;

    RAISE;
END;
/

但是“FOR r_mview IN c_mviews LOOP”语句生成以下错误:

Report error -
ORA-06502: PL/SQL: errore  di numero o valore
ORA-06512: a line 35
ORA-06512: a line 16
ORA-06512: a line 16
06502. 00000 -  "PL/SQL: numeric or value error%s"
*Cause:    An arithmetic, numeric, string, conversion, or constraint error
           occurred. For example, this error occurs if an attempt is made to
           assign the value NULL to a variable declared NOT NULL, or if an
           attempt is made to assign an integer larger than 99 to a variable
           declared NUMBER(2).
*Action:   Change the data, how it is manipulated, or how it is declared so
           that values do not violate constraints.

错误是在具有 QUERY_LEN = 39000 的物化视图上引发的。

我该如何解决这个问题?

非常感谢。

我认为您没有正确使用 UTL_FILE。 putf() 过程用于编写和格式化(使用 printf() 样式)。尝试只使用 put() 代替。我在我的数据库上执行了 运行 你的脚本,它使用 putf() 和 put() 执行得很好,但 put() 更合适。

另外,请注意 QUERY 是一个 LONG。如果您有超过 32k 的查询,我认为您会得到您所看到的错误。有一些很棒的文章 online 关于 LONG 的使用有多糟糕。

我认为最简单的方法是使用 CREATE TABLE 将 LONG 转换为 CLOB,读取 table 然后删除它。这是执行此操作的例程。它将创建 all_mviews 的副本并将查询转换为 CLOB 并将其以块的形式写入每个视图的文件中。

DECLARE
  v_out_dir_name      VARCHAR2(30) := 'MVIEW';
  v_count_object_elab NUMBER := 0;
  v_cursor            SYS_REFCURSOR;
  v_file              utl_file.file_type;
  v_start             INTEGER;
  v_buffer            VARCHAR2(1024);
  v_file_name         VARCHAR2(1024);
  v_query             CLOB;

  table_or_view_does_not_exist EXCEPTION;
  PRAGMA EXCEPTION_INIT(table_or_view_does_not_exist,
                        -00942);

BEGIN
  BEGIN
    EXECUTE IMMEDIATE 'DROP TABLE all_mviews_clob';
  EXCEPTION
    WHEN table_or_view_does_not_exist THEN
      NULL;
  END;

  EXECUTE IMMEDIATE 'CREATE TABLE all_mviews_clob AS SELECT mview_name, to_lob(query) AS query FROM all_mviews';

  OPEN v_cursor FOR q'[SELECT lower(mview_name) || '.sql' AS file_name,
           query AS script
      FROM all_mviews_clob]';

  LOOP
    FETCH v_cursor
      INTO v_file_name,
           v_query;
    EXIT WHEN v_cursor%NOTFOUND;

    v_file := utl_file.fopen(location  => v_out_dir_name,
                             filename  => v_file_name,
                             open_mode => 'w');

    v_start := 1;
    FOR i IN 1 .. ceil(dbms_lob.getlength(lob_loc => v_query) / 1024)
    LOOP
      v_buffer := dbms_lob.substr(lob_loc => v_query,
                                  amount  => 1024,
                                  offset  => v_start);

      IF v_buffer IS NOT NULL THEN
        utl_file.put(file   => v_file,
                     buffer => v_buffer);
        utl_file.fflush(file => v_file);
      END IF;

      v_start := v_start + 1024;
    END LOOP;

    utl_file.fclose(v_file);
    v_count_object_elab := v_count_object_elab + 1;
  END LOOP;

  IF v_count_object_elab = 0 THEN
    dbms_output.put_line('no mviews');
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    dbms_output.put_line('eror = ' || SQLERRM);

    IF utl_file.is_open(v_file) THEN
      utl_file.fclose(v_file);
    END IF;

    RAISE;
END;
/