#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