我正在通过SQLLDR将一些数据加载到Oracle。源文件是“管道分隔”。
FIELDS TERMINATED BY '|'
但是有些记录在数据中包含管道字符,而不是分隔符。因此,它会将 indata 管道字符理解为字段终止符,从而中断了正确的记录加载。
你能指点我解决这个问题的方向吗?
数据文件大约为9 GB,因此很难手动编辑。
例如,
已加载的行
ABC | 1234567 | STR 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 :(得分: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')"
这个正则表达式采用垂直条分隔的六个捕获组(括号内)(我必须将其转义,否则它在regexp中表示OR)。除第三组之外的所有组都不能包含竖线([^|]*
),第三组可能包含任何内容(.*
),正则表达式必须从行的开头到结尾(^
和$
)。
通过这种方式,我们确信第三组将吃掉所有多余的分离器。这只能起作用,因为您只有一个可能包含分隔符的字段。如果要进行校对,可以指定第四组以数字开头(在第四个带括号的块的开头包括\d
)。
我将所有反斜杠加倍,因为我们在双引号表达式中,但我不确定我应该这样做。
答案 1 :(得分: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 :(得分: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和last chunk。
您可以尝试使用“,”分隔符sqlldr new_file。
<强>更新强> 该命令可以放在像(并命名为parse.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