L oop курсор ALL_MVIEWS генерирует PL / SQL Ошибка ORA-06502 - PullRequest
0 голосов
/ 06 апреля 2020

Я написал процедуру, которая занимается записью содержимого столбца QUERY ALL_MVIEWS в файл:

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 L OOP* Оператор 1006 * "генерирует следующую ошибку:

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.

Как решить проблему?

Большое спасибо заранее.

1 Ответ

0 голосов
/ 06 апреля 2020

Я не думаю, что вы используете UTL_FILE правильно. Процедура putf () предназначена для записи и форматирования (с использованием стиля printf ()). Попробуйте использовать просто положить () вместо этого. Я запустил ваш сценарий в своей базе данных, и он прекрасно работал с putf () и put (), но более подходящим является put ().

Кроме того, помните, что QUERY - это LONG. Если у вас есть запрос более 32k, я думаю, вы получите ошибку, которую видите. В сети есть несколько замечательных статей о том, как ужасно работать с LONG.

Я думаю, что проще всего конвертировать LONG в CLOB с помощью CREATE 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;
/
...