2012-01-20 2 views
3

Я загружаю некоторые данные в Oracle через SQLLDR. Исходный файл является «ограниченным контуром».SQL * Loader: Работа с разделителями в данных

FIELDS TERMINATED BY '|' 

Но некоторые записи содержат символ трубы в данных, а не как разделитель. Таким образом, он прерывает правильную загрузку записей, поскольку понимает indata символы трубы в качестве терминатора поля.

Можете ли вы указать мне направление для решения этой проблемы?

Файл данных составляет около 9 ГБ, поэтому его трудно редактировать вручную.

Например,

нагруженное ряд:

АВС | 1234567 | СТР 9 R 25 | 98734959,32 | 28.12.2011

Отклонено Ряд:

DE4 | 2346543 | WE | 454 | 956584,84 | 28.11.2011

Ошибка:

Rejected - Error on table HSX, column DATE_N. 
ORA-01847: day of month must be between 1 and last day of month 

DATE_N колонна является последним.

+0

Можете ли вы привести пример линии с проблемами? –

+1

Являются ли поля с трубками '' 'заключенными в кавычки? например 'DATA1 | DATA2 |" DATAWITH | PIPE "| DATA3'. В этом случае вы можете использовать 'FIELDS TERMINATED BY '|' OPTIONALLYED BY '"'' –

+0

@FlorinGhita обновлено – bonsvr

ответ

3

Вы не можете использовать любой разделитель, и сделать что-то вроде:

field FILLER, 
col1 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\1')", 
col2 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\2')", 
col3 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\3')", 
col4 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\4')", 
col5 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\5')", 
col6 EXPRESSION "REGEXP_REPLACE(:field,'^([^|]*)\\|([^|]*)\\|(.*)\\|([^|]*)\\|([^|]*)\\|([^|]*)$', '\\6')" 

Это регулярное выражение принимает шесть захвата групп (в круглых скобках), разделенных вертикальной полосой (мне пришлось ее избежать, иначе это означает OR в регулярном выражении). Все группы, кроме третьего, не могут содержать вертикальную полосу ([^|]*), третья группа может содержать что угодно (.*), а регулярное выражение должно охватывать от начала до конца строки (^ и $).

Таким образом, мы уверены, что третья группа будет есть все лишние разделители. Это работает только потому, что у вас есть только одно поле, которое может содержать разделители. Если вы хотите проверить проверку, вы можете, например, указать, что четвертая группа начинается с цифры (включая \d в начале четвертого блока в скобках).

Я удвоил все обратные косые черты, потому что мы находимся внутри выражения с двойным кавычкой, но я не уверен, что должен.

+0

что это? –

+0

FILLER поглощает всю строку данных, а регулярное выражение разбивает его на 6 значимых частей. Если вы не знаете, что такое регулярное выражение, найдите здесь тег regex. – Benoit

+0

Хорошо, я понял, +1 :). Я знаю, что такое регулярное выражение, но я никогда не использовал функции Oracle REGEXP. Это похоже на то, что я сделал с awk. Вы сделали это с регулярными выражениями. –

2

Мне кажется, что SQL * Loader не может обрабатывать ваш файл из-за третьего поля, которое: может содержать разделитель, не окружено кавычками и имеет переменную длину. Вместо этого, если предоставленные вами данные являются точным примером, я могу предоставить пример обходного пути. Во-первых, создайте таблицу с одним столбцом VARCHAR2 с длиной, равной максимальной длине любой строки в вашем файле. Затем просто загрузите весь файл в эту таблицу. Оттуда вы можете извлечь каждую колонку запроса, такие как:

with CTE as 
     (select 'ABC|1234567|STR 9 R 25|98734959,32|28.12.2011' as CTETXT 
      from dual 
     union all 
     select 'DE4|2346543|WE| 454|956584,84|28.11.2011' from dual) 
select substr(CTETXT, 1, instr(CTETXT, '|') - 1) as COL1 
     ,substr(CTETXT 
      ,instr(CTETXT, '|', 1, 1) + 1 
      ,instr(CTETXT, '|', 1, 2) - instr(CTETXT, '|', 1, 1) - 1) 
     as COL2 
     ,substr(CTETXT 
      ,instr(CTETXT, '|', 1, 2) + 1 
      ,instr(CTETXT, '|', -1, 1) - instr(CTETXT, '|', 1, 2) - 1) 
     as COL3 
     ,substr(CTETXT, instr(CTETXT, '|', -1, 1) + 1) as COL4 
    from CTE 

Это не идеальное (хотя это может быть адаптировано к SQL * Loader), но нужно будет немного поработать, если у вас есть несколько столбцов или если ваши третий поле не то, что я думаю. Но это начало.

2

Хорошо, я рекомендую вам разобрать файл и заменить разделитель. В командной строке в Unix/Linux вы должны сделать:

cat current_file | awk -F'|' '{printf("%s,%s,", $1, $2); for(k=3;k<NF-2;k++) printf("%s|", $k); printf("%s,%s,%s", $(NF-2),$(NF-1),$NF);print "";}' > new_file 

Эта команда не изменит текущий файл. Создает новый файл, разделенный запятой, с пятью полями. Он разбивает входной файл на «|» и возьмите сначала, во-вторых, что-нибудь, что касается antelast, antelast и последний кусок.

Вы можете попробовать sqlldr new_file с разделителем ",".

ОБНОВЛЕНИЕ: Команда может быть помещена в сценарий, подобный (и названный синтаксический анализ.AWK)

#!/usr/bin/awk 
# parse.awk 
BEGIN {FS="|"} 
{ 
printf("%s,%s,", $1, $2); 

for(k=3;k<NF-2;k++) 
     printf("%s|", $k); 

printf("%s,%s,%s\n", $(NF-2),$(NF-1),$NF); 
} 

и вы можете запустить следующим образом:

cat current_file | awk -f parse.awk > new_file 
+0

, используя выигрыш 7. спасибо в любом случае. – bonsvr

+0

ничего себе. в любом случае, если у вас есть unix/linux под рукой, это может быть быстрее исправить файл таким образом :) –