В дополнение к уже указанным ошибкам у вашей функции есть, по крайней мере, пара проблем. Я полагаю, что самой большой проблемой является ваше неправильное понимание функции Substring , в частности третьего параметра. Третий параметр опционально указывает желаемую длину , а не конечную позицию. Например, переменная v5 определена как дата, но значение установлено как «v5: = Substr (v_row, 27, 35);». У вас действительно есть дата длиной 35 символов. Кроме того, если третий параметр пропущен, результирующее значение распространяется от второго параметра до конца строки. Таким образом, v7 продолжается от позиции 43 до конца строки. V8, V9 - это числа, состоящие из 48 и 51 цифр соответственно, и каждое поле перекрывает следующее.
Другая большая проблема - ошибка NO_DATA_FOUND. У вас есть три места, где это может произойти (выбор), и 1, где это произойдет (utl_file.Get_line - вот как utl_file указывает на конец файла). Как структурировано, вы не можете знать, что послужило причиной этой ошибки. Далее я предлагаю метод решения этой проблемы. Я разбиваю каждый из этих элементов на собственную процедуру. Я оставляю проблему с подстрокой для вашего разрешения.
До этого немного философии. Имена и классификации важны. Имена должны описывать то, что представляют, но V1, V2 ... нет; так что вместо v5 возможно v_shipped_dt. Аналогичным образом объявление процедуры против функции должно быть сделано в зависимости от цели процедуры. Процедуры выполняются, функции получают вещи. Кажется, цель здесь состоит в том, чтобы загрузить данные, а не возвращать логическое значение. Поэтому я сделал это процедурой (она сообщает через выходной параметр). (Обычно я бы этого даже не сделал. Он успешно работает и ничего не возвращает или если не может вызвать исключение. Но это, возможно, стилист c.)
create or replace procedure load_order_file
( ldir varchar2
, lfile varchar2
, result out varchar2
)
as
customer_error exception;
employee_error exception;
item_error exception;
f utl_file.file_type;
v_row varchar2(2000);
v1 number;
v2 number;
v3 number;
v4 date;
v5 date;
v6 number;
v7 number;
v8 number;
v9 number;
EOF_Reached Boolean ;
-- procedure to handle all file processing
procedure load_order_buffer
is
begin
if f is null or not util_file.is_open(f)
then
f := utl_file.fopen(ldir, lfile, 'R');
EOF_Reached := False;
end if ;
utl_file.get_line(f, v_row);
exception
when no_data_found then
EOF_Reached := True;
util_file.fclose(f);
end load_order_buffer;
-- procedure to split file line into local variables
procedure parse_buffer
is
begin
v1 := substr(v_row, 1, 4);
v2 := substr(v_row, 6, 9);
v3 := substr(v_row, 11, 12);
v4 := substr(v_row, 15, 23);
v5 := substr(v_row, 27, 35);
v6 := substr(v_row, 38, 41);
v7 := substr(v_row, 43);
v8 := substr(v_row, 45, 48);
v9 := substr(v_row, 50, 51);
end parse_buffer;
-- procedures to validate customer, employee, and inventory
procedure validate_customer(cust_no_in number)
is
l_exists varchar2(1);
begin
select null
into l_exists
from customers
where cno = cust_no_in;
exception
when no_data_found then
raise customer_error;
end validate_customer;
procedure validate_employee(employee_no_in number)
is
l_exists varchar2(1);
begin
select null
into l_exists
from employees
where employeeno = employee_no_in;
exception
when no_data_found then
raise employee_error;
end validate_employee;
procedure validate_inventory(inventory_no_in number)
is
l_exists varchar2(1);
begin
select null
into l_exists
from inventory
where itemno = inventory_no_in;
exception
when no_data_found then
raise item_error;
end validate_inventory;
-- Main
begin
-- set up initial assumptions;
result := 'Failed';
EOF_Reached := False;
loop
load_order_buffer;
exit when EOF_Reached;
parse_buffer;
validate_customer(v2);
validate_employee(v3);
validate_inventory(v6);
validate_inventory(v8);
-- everything valid create transaction
insert into transactions
(tid, orderno, cno, employeeno, received,
shipped, itemno1, quantity1, itemno2, quantity2)
values (sequence_tid.nextval, v1, v2, v3, v4, v5,
v6, v7, v8, v9);
end loop;
result := 'Success';
exception
when customer_error then
dbms_output.put_line('Customer not found in parent Customer table');
when employee_error then
dbms_output.put_line('Employee not found in Employee table');
when item_error then
dbms_output.put_line('Item not found in inventory table');
when others then
dbms_output.put_line('Error code:'
|| sqlcode
|| '. Error Message: '
|| sqlerrm);
end load_order_file ;
/
Вот тестовый драйвер
declare
result varchar2(8);
begin
load_order_file('forQues','items.txt');
dbms_output.put_line('Load Order file terminated with ' || result);
if result <> 'Success'
then
rollback;
end if ;
end ;
Поскольку вы не предоставили ни таблицы DDL, ни данных образца, это не проверено . Удачи.