Oracle SQL-Loader在值中有效地处理内部双引号

时间:2017-01-02 18:17:25

标签: oracle sql-loader

我遇到了一些Oracle SQL Loader挑战,并寻找一种高效而简单的解决方案。 我要加载的源文件是管道|分隔的,其中值由双引号"括起来。 问题似乎是某些值包含内部双引号。

例如:..."|"a":"b"|"...

这会导致我的记录被拒绝:

no terminator found after TERMINATED and ENCLOSED field

网上有各种解决方案,但似乎不合适:

[1] 我试图在引用引号时替换所有内部双引号, 但似乎在控制文件上的太多字段上应用此功能时 (我有~2000 +字段并使用FILLER只加载一个子集) 装载机再次抱怨:

SQL*Loader-350: Syntax error at line 7.
Expecting "," or ")", found ",".
field1  char(36) "replace(:field1,'"','""')",

(我不知道为什么,但是当在一个狭窄的列子集上应用此解决方案时,它似乎确实有效)

事情是,所有字段都可能包含内部双引号。

[2] 我可以在省略全局optionally enclosed by '"'时加载所有数据,但随后所有封闭引号都成为目标表中数据的一部分。

[3] 我可以省略全局optionally enclosed by '"'语句并将其仅放在选定的字段中, 尝试"replace(:field1,'"','""')"对剩余部分的陈述,但这很难实现, 因为我无法知道包含内部双引号的可疑字段是什么。

这是我的问题:

  1. 有没有简单的方法来说服加载器小心处理内部双引号(当值被它们包围时)?

  2. 如果我被迫修复数据广告,是否有一个单行Linux命令只将内部双引号转换为另一个字符串/ char, 说,单引号?

  3. 如果我被迫用引号加载数据到目标表,是否有一种简单的方法可以从所有字段中删除封闭的双引号, 一下子(表格有~1000列)。对于非常大的表格来说,解决方案是否具有实际性能?

1 个答案:

答案 0 :(得分:3)

如果您在封闭的字段中没有管道,则可以从控制文件中执行此操作。如果你可以在一个字段中同时包含管道和双引号,那么我认为你别无选择,只能对这些文件进行预处理。

你的解决方案[1],替换双引号with an SQL operator,发生得太晚而无法发挥作用;在执行SQL步骤之前,SQL * Loader已经解释了分隔符和附件。您的解决方案[2],忽略外壳,将与[1]结合使用 - 直到其中一个字段确实包含管道字符。解决方案[3]与全局使用[1]和/或[2]具有相同的问题。

specifying delimiters的文档提到:

  

有时,作为分隔符的标点符号也必须包含在数据中。为了实现这一点,两个相邻的分隔符字符被解释为字符的单个匹配项,并且该字符包含在数据中。

换句话说,如果您在字段内重复双引号,那么它们将被转义并显示在表格数据中。由于您无法控制数据生成,因此您可以预处理您使用转义双引号替换所有双引号的文件。除非您不想替换所有,否则不应转发那些真正的外壳。

您可以使用正则表达式来定位相关字符将跳过其他人。不是我强大的领域,但我认为你可以用lookahead and lookbehind assertions来做到这一点。

如果您有一个名为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"        

希望与原始数据匹配。可能有边缘情况不起作用(如双引号后面跟 字段中的管道),但是对于尝试解释某人的行为有限制别的数据......当然,也可能有(更多)更好的正则表达式。

如果数据文件是(或可以)在Oracle目录中并且您具有正确的权限,则还可以考虑使用an external table而不是SQL * Loader。您仍然需要修改该文件,但您可以使用preprocessor指令自动执行该操作,而不是在调用SQL * Loader之前显式执行此操作。