Код:
DECLARE
-- загрузка комментария в карточку Супермага
k_outF UTL_FILE.FILE_TYPE;
k_inF UTL_FILE.FILE_TYPE;
k_Dir VARCHAR2(20) := 'SM_DATA'; -- каталог данных на СЕРВЕРЕ; UTL_FILE работает только с данными на самом сервере, не на клменте.
-- предварительно требуется данный каталог указать в базе.
-- например (сервер на linux, поэтому пути такие)
-- create or replace directory SM_DATA as '/app/sql';
-- или под виндой
-- create or replace directory SM_DATA as 'c:\sql\';
-- имя directory лучше всегда указывать большими буквами. иначе можно долго ловить ошибку.
k_outN VARCHAR2(20) := 'cmnt.log'; -- имя выходного файла (журнал работы)
k_inN VARCHAR2(20) := 'cmnt.txt'; -- имя файла входных данных
tab char(1) := chr(9); -- разделитель полей
cn VARCHAR2(511); -- загружаемая строка
cac NUMBER(3); -- позиция разделителя полей
c_a VARCHAR2(40); -- артикул Супермага
c_c VARCHAR2(255); -- комментарий
chk NUMBER(12); -- для проверки артикула
testonly boolean := TRUE; -- только тест, ничего не меняем в базе данных, только пишем журнал
-- testonly boolean := FALSE; -- рабочий режим, вносим изменения в базу
BEGIN
--загрузка в Супермаг
-- открываем файлы
k_inF := UTL_FILE.FOPEN(k_Dir,k_inN,'r');
k_outF := UTL_FILE.FOPEN(k_Dir,k_outN,'w');
-- в цикле читаем входящий файл, разбираем очередную строку на информационные поля
loop
begin
UTL_FILE.GET_LINE(k_inF,cn); -- считываем строку
exception
WHEN NO_DATA_FOUND THEN EXIT; -- выйдем из цикла, когда кончится файл
end;
-- отладка. выводим в журнал считанную строку
if testonly then
UTL_FILE.PUTF(k_outF,cn||'\n'); -- запись строки
-- все отладочные записи надо сразу сбросить из буфера записи на диск.
-- это позволяет понять, что поледнее сработало правильно. тогда будет понятно, на чем сломалось.
UTL_FILE.FFLUSH(k_outF); -- сбрасываем буфер файла на диск
end if;
cac := instr(cn,tab); -- находим позицию разделителя
c_a := SUBSTR(cn,1,cac-1); -- выделяем из строки артикул
cn := SUBSTR(cn,cac + 1); -- остаток строки без артикула
-- если полей много, то предыдущие три строки повторяем сколько нужно
-- отладка. выводим в журнал артикул
if testonly then
UTL_FILE.PUTF(k_outF,c_a||'\n');
UTL_FILE.FFLUSH(k_outF);
end if;
-- последнее поле равно остатку строки
c_c := cn; -- в строке остался только комментарий
-- отладка. выводим в журнал комментарий
if testonly then
UTL_FILE.PUTF(k_outF,c_c||'\n');
UTL_FILE.FFLUSH(k_outF);
end if;
-- если во входящем файле есть числовые поля, то тут делаем замену запятых на точки для корректной работы TO_NUMBER
-- или наоборот; зависит от кодировок
-- b_s_novat := REPLACE(b_s_novat,',','.');
-- b_s_total := REPLACE(b_s_total,',','.');
-- b_s_quant := REPLACE(b_s_quant,',','.');
-- считаем в базе карточки с таким ариткулом
SELECT count(*)
INTO chk
FROM SMCard
WHERE Article=c_a;
-- нашли одну карточку. всё хорошо. обновляем
if chk=1 then
if NOT testonly then
update SMCard set CardComment=c_c where Article=c_a;
commit;
end if;
UTL_FILE.PUTF(k_outF,'комментарий обновлен: '||tab||c_a||tab||c_c||'\n');
UTL_FILE.FFLUSH(k_outF);
else
UTL_FILE.PUTF(k_outF,'артикул в базе не найден: '||tab||c_a||tab||c_c||'---------------------------\n');
UTL_FILE.FFLUSH(k_outF);
end if;
end loop;
-- закрываем файлы
UTL_FILE.FCLOSE(k_inF);
UTL_FILE.FCLOSE(k_outF);
--------------------------------------------------
EXCEPTION
WHEN UTL_FILE.INVALID_PATH THEN
RAISE_APPLICATION_ERROR(-20100, 'Invalid Path');
WHEN UTL_FILE.INVALID_MODE THEN
RAISE_APPLICATION_ERROR(-20101, 'Invalid Mode');
WHEN UTL_FILE.INVALID_OPERATION THEN
RAISE_APPLICATION_ERROR(-20101, 'Invalid Operation');
WHEN UTL_FILE.INVALID_FILEHANDLE THEN
RAISE_APPLICATION_ERROR(-20300, 'Invalid File Handle');
WHEN UTL_FILE.WRITE_ERROR THEN
RAISE_APPLICATION_ERROR(-20301, 'Write Error');
WHEN UTL_FILE.INTERNAL_ERROR THEN
RAISE_APPLICATION_ERROR(-20302, 'Internal Error');
END;
-- последние две строки скрипта раскомментировать для запуска sqlplus из командной строки с передачей имени скрипта как параметра:
-- sqlplus пользователь/пароль@база @c:\sql\cmnt.sql
--/
--exit;