Oracle SQL-加载程序有效处理值中的内部双引号
Oracle SQL-Loader handling efficiently internal Double Quotes in values
我有一些 Oracle SQL 加载程序挑战,正在寻找一种高效且简单的解决方案。
我要加载的源文件是管道 |
分隔的,其中值用双引号 "
括起来。
问题似乎是某些值包含内部双引号。
例如:..."|"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 '"'
时加载所有数据,但随后所有引号都会成为目标 table.
中数据的一部分
[3]
我可以省略全局 optionally enclosed by '"'
语句并将其仅放在选定的字段中,
while 尝试对余数进行 "replace(:field1,'"','""')"
声明,但这很难实现,
因为我无法提前知道哪些可疑字段包含内部双引号。
这是我的问题:
有没有简单的方法可以说服加载程序小心处理内部双引号(当值被它们括起来时)?
如果我被迫临时修复数据,是否有单行 Linux 命令仅将内部双引号转换为另一个 string/char,
比如,单引号?
如果我被迫将带有引号的数据加载到目标 table,是否有一种简单的方法可以从所有字段中删除封闭的双引号,
一次全部(table 有 ~1000 列)。对于非常大的tables,解决方案的实际性能是否明智?
如果您从未在封闭的字段中使用管道,您可以从控制文件中进行操作。如果您可以在一个字段中同时使用竖线和双引号,那么不幸的是,我认为您别无选择,只能对文件进行预处理。
您的解决方案 [1],用于替换双引号 with an SQL operator,为时已晚,无法发挥作用; SQL*Loader 在执行 SQL 步骤之前已经解释了分隔符和附件。您的解决方案 [2] 忽略外壳,将与 [1] 结合使用 - 直到其中一个字段确实包含竖线字符。解决方案 [3] 与全局使用 [1] and/or [2] 存在相同的问题。
specifying delimiters 的文档提到:
Sometimes the punctuation mark that is a delimiter must also be included in the data. To make that possible, two adjacent delimiter characters are interpreted as a single occurrence of the character, and this character is included in the data.
换句话说,如果您在 字段中重复 双引号,那么它们将被转义并出现在 table 数据中。由于您无法控制数据生成,因此您可以预处理您获得的文件以用转义双引号替换所有双引号。除非你不想替换它们中的 所有 - 那些实际上是真正的外壳不应该被转义。
您可以使用正则表达式来定位相关字符,将跳过其他字符。不是我的强项,但我认为你可以用 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"
希望与您的原始数据匹配。可能存在不起作用的边缘情况(例如双引号后跟竖线 在 字段中)但是尝试解释其他人的数据时您可以做的事情是有限的... 当然,也可能有(好得多)更好的正则表达式模式。
您还可以考虑使用 an external table instead of SQL*Loader, if the data file is (or can be) in an Oracle directory and you have the right permissions. You still have to modify the file, but you could do it automatically with the preprocessor
指令,而不需要在调用 SQL*Loader.
之前显式地这样做
我有一些 Oracle SQL 加载程序挑战,正在寻找一种高效且简单的解决方案。
我要加载的源文件是管道 |
分隔的,其中值用双引号 "
括起来。
问题似乎是某些值包含内部双引号。
例如:..."|"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 '"'
时加载所有数据,但随后所有引号都会成为目标 table.
[3]
我可以省略全局 optionally enclosed by '"'
语句并将其仅放在选定的字段中,
while 尝试对余数进行 "replace(:field1,'"','""')"
声明,但这很难实现,
因为我无法提前知道哪些可疑字段包含内部双引号。
这是我的问题:
有没有简单的方法可以说服加载程序小心处理内部双引号(当值被它们括起来时)?
如果我被迫临时修复数据,是否有单行 Linux 命令仅将内部双引号转换为另一个 string/char, 比如,单引号?
如果我被迫将带有引号的数据加载到目标 table,是否有一种简单的方法可以从所有字段中删除封闭的双引号, 一次全部(table 有 ~1000 列)。对于非常大的tables,解决方案的实际性能是否明智?
如果您从未在封闭的字段中使用管道,您可以从控制文件中进行操作。如果您可以在一个字段中同时使用竖线和双引号,那么不幸的是,我认为您别无选择,只能对文件进行预处理。
您的解决方案 [1],用于替换双引号 with an SQL operator,为时已晚,无法发挥作用; SQL*Loader 在执行 SQL 步骤之前已经解释了分隔符和附件。您的解决方案 [2] 忽略外壳,将与 [1] 结合使用 - 直到其中一个字段确实包含竖线字符。解决方案 [3] 与全局使用 [1] and/or [2] 存在相同的问题。
specifying delimiters 的文档提到:
Sometimes the punctuation mark that is a delimiter must also be included in the data. To make that possible, two adjacent delimiter characters are interpreted as a single occurrence of the character, and this character is included in the data.
换句话说,如果您在 字段中重复 双引号,那么它们将被转义并出现在 table 数据中。由于您无法控制数据生成,因此您可以预处理您获得的文件以用转义双引号替换所有双引号。除非你不想替换它们中的 所有 - 那些实际上是真正的外壳不应该被转义。
您可以使用正则表达式来定位相关字符,将跳过其他字符。不是我的强项,但我认为你可以用 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"
希望与您的原始数据匹配。可能存在不起作用的边缘情况(例如双引号后跟竖线 在 字段中)但是尝试解释其他人的数据时您可以做的事情是有限的... 当然,也可能有(好得多)更好的正则表达式模式。
您还可以考虑使用 an external table instead of SQL*Loader, if the data file is (or can be) in an Oracle directory and you have the right permissions. You still have to modify the file, but you could do it automatically with the preprocessor
指令,而不需要在调用 SQL*Loader.