Повторная инициализация переменной / записи в PL / SQL во время цикла

#loops #plsql #io

#циклы #plsql #io

Вопрос:

Чтобы создать анализатор PL / SQL для процесса ETL, в котором данные в основном кодируются в позиционном формате, мне необходимо прочитать файл построчно и добавить записи в таблицу в памяти (в области пакета) в текущую запись или в новую запись.

Позвольте мне кратко объяснить сценарий и правила грамматики: Мне нужно проанализировать сообщения о выравнивании банковских операций, которые имеют общедоступный стандартный формат (не могу найти документацию на английском языке, только этот и другие итальянские документы, хотя это должно быть стандартом для всего ЕС). В любом случае, вот некоторые объясненные правила:

  • Каждая запись в файле имеет длину 120 символов
  • Каждый файл начинается с записи «AL» (выравнивание)
  • Каждый файл заканчивается записью «EF» (конец файла)
  • Каждое сообщение о выравнивании начинается с записи «12» и заканчивается записью «70»
  • В зависимости от типа записи «12» сообщение может быть составлено из различных комбинаций других записей, таких как «30» и «40», «50», «45», «50» и «45» «50»

Пример (структурированный):

 AL record
    12 record
        45 record
    70 record
    12 record
        45 record
        50 record
    70 record
EF record
  

Я уже объявил MESSAGE таблицу PL / SQL CHAR(120) , которая должна инкапсулировать записи от 12 до 70 (включительно), они будут обработаны на более позднем этапе. Теперь у меня есть проблема с циклом, которую я мог бы легко решить на Java.

Как я могу повторно инициализировать переменную в PL / SQL? Вот псевдо-Java пример того, что мне нужно сделать

 String line;
List<String> alignment_message;
List<AlignmentMessage> table;
while (line = readline()) {
    if (line.substring(1,2)=="12") //Begin of message 
        alignment_message = new MESSAGE(); //******HOW DO I DO THIS????
    alignment_message.add(line); //Don't care about NPE ;-)

    if (line.substring(1,2)=="70") //End of message
        table.add(alignment_message);
}
  

В настоящее время я объявил в своей процедуре PL / SQL переменную msg типа MESSAGE . Если я делаю INSERT в эту переменную, а затем вводю INSERT эту переменную в таблицу, содержащую столбец типа MESSAGE (и пару других столбцов, которые я использую для предварительной обработки), как я могу выполнить новые INSERT операции в свежей новой переменной msg?

Спасибо

Ответ №1:

Если вы объявили MESSAGE как TABLE OF CHAR(120) , TABLE OF CHAR(120) INDEX BY BINARY_INTEGER или VARRAY(...) OF CHAR(120) , то вы можете сделать

 msg.DELETE;
  

Методы DELETE для вложенных таблиц, таблиц с индексацией и переменных удаляют из них все элементы.

Когда вы INSERT msg переходите к таблице, Oracle, похоже, хранит ее копию, а не ссылку на нее. Удаление всех элементов из msg не приведет к внезапному исчезновению данных в вашей таблице.

В качестве альтернативы, если MESSAGE это TABLE OF CHAR(120) или VARRAY(...) OF CHAR(120) , вы можете вызвать MESSAGE() конструктор, т.е.

 msg := MESSAGE();
  

Ответ №2:

 declare
  type message_t is table of char(120);
  v_message message_t := message_t('12 record', /* start */
                                   '40 record',
                                   '70 record', /* end */
                                   '12 record', /* start */
                                   '50 record',
                                   '51 record',
                                   '70 record'  /* end */
                                   );
  v_almessage message_t := message_t();
  v_i number := v_message.first;
begin
  while v_i <= v_message.last loop
    if v_message(v_i) = '12 record' then /* start of a block */
      dbms_output.put_line('start of a block');

      loop
        v_i := v_i   1;

        if v_message(v_i) = '70 record' then /* end of a block */
          dbms_output.put_line('end of a block');

          /* Do whatever processing you need to do. I just print collected
          messages. */
          for j in v_almessage.first .. v_almessage.last loop
            dbms_output.put_line('aligment message: ' || v_almessage(j)); 
          end loop;

          /* Reset collected messages. */
          v_almessage := message_t();

          exit;
        end if;

        /* Collect block's aligment messages. */
        v_almessage.extend(1);
        v_almessage(v_almessage.last) := v_message(v_i);
      end loop;

    end if;

    v_i := v_i   1;
  end loop;

end;
/
  

С принтами:

 start of a block
end of a block
aligment message: 40 record
start of a block
end of a block
aligment message: 50 record
aligment message: 51 record