如果封闭字段中从未有管道,则可以从控制文件中执行此操作。不幸的是,如果您可以在一个字段中同时使用管道和双引号,那么我认为您别无选择,只能预处理文件。
您的解决方案 [1],替换双引号使用 SQL 运算符,发生得太晚而无用;在执行 SQL 步骤之前,SQL*Loader 已经解释了分隔符和括弧。您的解决方案 [2](忽略外壳)将与 [1] 结合使用 - 直到其中一个字段确实包含管道字符。解决方案 [3] 与全局使用 [1] 和/或 [2] 存在相同的问题。
的文档指定分隔符提到:
有时,作为分隔符的标点符号也必须包含在数据中。为了实现这一点,两个相邻的分隔符被解释为该字符的一次出现,并且该字符包含在数据中。
换句话说,如果你重复双引号inside然后字段将被转义并出现在表数据中。由于您无法控制数据生成,因此您可以预处理获得的文件,以将所有双引号替换为转义双引号。除非你不想更换all其中 - 那些实际上是真正的外壳的不应该被逃脱。
您可以使用正则表达式来定位相关字符,从而跳过其他字符。不是我的强项,但我认为你可以做到这一点前瞻和后瞻断言.
如果你有一个名为orig.txt
包含:
"1"|A|"B"|"C|D"
"2"|A|"B"|"C"D"
3|A|""B""|"C|D"
4|A|"B"|"C"D|E"F"G|H""
你可以这样做:
perl -pe 's/(?<!^)(?<!\|)"(?!\|)(?!$)/""/g' orig.txt > new.txt
它查找前面没有行起始锚点或管道字符的双引号;并且后面没有管字符或线端锚;并仅替换那些带有转义(双)双引号的内容。这会让new.txt
包含:
"1"|A|"B"|"C|D"
"2"|A|"B"|"C""D"
3|A|"""B"""|"C|D"
4|A|"B"|"C""D|E""F""G|H"""
字段开头和结尾的双引号不会被修改,但中间的双引号现在会被转义。如果您随后使用带双引号的控制文件加载该文件:
load data
truncate
into table t42
fields terminated by '|' optionally enclosed by '"'
(
col1,
col2,
col3,
col4
)
那么你最终会得到:
select * from t42 order by col1;
COL1 COL2 COL3 COL4
---------- ---------- ---------- --------------------
1 A B C|D
2 A B C"D
3 A "B" C|D
3 A B C"D|E"F"G|H"
希望与您的原始数据匹配。可能存在不起作用的边缘情况(例如双引号后跟管道within一个字段),但是尝试解释其他人的数据时可以做的事情是有限的......当然,也可能有(更多)更好的正则表达式模式。
您还可以考虑使用外部表如果数据文件位于(或可以位于)Oracle 目录中并且您具有正确的权限,则可以使用 SQL*Loader 来代替 SQL*Loader。您仍然需要修改该文件,但是您可以使用以下命令自动完成此操作preprocessor指令,而不需要在调用 SQL*Loader 之前显式执行此操作。