输入文件在同一行中最多有34种不同的记录类型。
文件是以管道分隔的,每个记录类型用'〜'分隔(原始记录类型除外。
并非所有34种记录类型都包含在每一行中,我不需要全部。
所有记录类型都将按指定的顺序发送,但不会始终发送所有记录类型。第一个记录类型是强制性的,将始终发送。在34种类型中,只有7种是强制性的。
每个记录类型都有预定义数量的字段,如果客户端和负载之间没有适当的准备时间,则永远不应偏离该定义。
将根据所需的记录类型构建Oracle表,其中包含所有必需的列。因此,一行将包含与输入文件类似的每种记录类型的信息,但还会包含来自某些未包含在输入中的记录类型的列的空值。
我正在寻找的最终结果是一种对输入文件执行条件格式化的方法,以便生成一个输出,可以通过sqlldr简单地加载到shell脚本中,而不是通过PL / SQL(我想要的)我的非PL / SQL同事能够解决/修复加载过程中遇到的任何问题。)
包含3条记录的小例子(本例中数据类型无关紧要):
Record Types: AA, BB, CC, DD, EE, FF
AA has 5 fields (Mandatory)
BB has 2 fields (Optional)
CC has 3 fields (Optional)
DD has 6 fields (Optional)
EE has 4 fields (Optional)
FF has 2 fields (Not needed. Skipping in output)
GG has 4 fields (Optional)
AA|12345|ABCDE|67890|FGHIJ|~BB|12345|~CC|ABCDE|12345|~DD|A|B|C|D|E|~EE|1|2|3|~FF|P|~GG|F|R|T
AA|23456|BCDEF|78901|GHIJK|~CC|BCDEF|23456|~EE|2|3|4|~GG|R|F|G
AA|34567|CDEFG|89012|HIJKL|~DD|B|C|D||~FF|Q
第1行没有问题,因为它有所有可用的记录类型,但第2行和第3行没有。因此需要修改它们以包含缺少的记录类型。整体输出需要看起来像这样:
AA|12345|ABCDE|67890|FGHIJ|~BB|12345|~CC|ABCDE|12345|~DD|A|B|C|D|E|~EE|1|2|3|~GG|F|R|T
AA|23456|BCDEF|78901|GHIJK|~BB||~CC|BCDEF|23456|~DD||||||~EE|2|3|4|~GG|R|F|G
AA|34567|CDEFG|89012|HIJKL|~BB||~CC|||~DD|B|C|D||~EE||||~GG|||
我已经开始记录每条记录,将其拆分为自己的文件,然后使用:
typeset -i count=0
while read record
do
newfile="`echo $file`.$count.dat"
echo $record | sed 's/|~/\n/g' > $newfile
count=$count+1
done < $file
将每个记录类型放在所述文件中的自己的行上,但是将其重新组合成一行并显示所有可能的字段非常棘手。这显然不是最好的方法,因为每个文件可以有几千条记录,这会产生几千个文件,但我用它作为起点来降低逻辑。
有什么想法吗?
答案 0 :(得分:2)
这是一个可执行的awk脚本解决方案,它不是非常严格,但可以帮助您入门:
#!/usr/bin/awk -f
BEGIN { FS=OFS="~" }
FNR==NR {
dflts[$1] = create_empty_field($1,$2)
if( $3 ~ /req|opt/ ) fld_order[++fld_cnt] = $1
fld_rule[$1] = $3
next
}
{
flds = ""
j = 1
for(i=1; i<=fld_cnt; i++) {
j = skip_flds( j )
if($j !~ ("^" fld_order[i])) fld = dflts[fld_order[i]]
else { fld = $j; j++ }
flds = flds (flds=="" ? "" : OFS) fld
}
print flds
}
function create_empty_field(name, cnt, fld, i) {
fld = name
for(i=1; i<=cnt; i++) { fld = fld "|" }
return( fld )
}
function skip_flds(fnum, name) {
name = $fnum
sub(/\|.*$/, "", name)
while(fld_rule[name] == "skp") {
fnum++
name = $fnum
sub(/\|.*$/, "", name)
}
return( fnum )
}
它需要一个额外的输入文件来指定每种类型字段的默认值,我称之为&#34; known_flds&#34;
AA~5~req
BB~2~opt
CC~3~opt
DD~6~opt
EE~4~opt
FF~2~skp
GG~4~opt
与数据文件具有相同的分隔符,因为我不想在脚本或输入文件之间添加FS
切换。它是您的字段要求的编码。最后一个字段是:
当awk.script
成为可执行文件并像./awk.script known_flds data
一样运行时,我得到以下输出:
AA|12345|ABCDE|67890|FGHIJ|~BB|12345|~CC|ABCDE|12345|~DD|A|B|C|D|E|~EE|1|2|3|~GG|F|R|T
AA|23456|BCDEF|78901|GHIJK|~BB||~CC|BCDEF|23456|~DD||||||~EE|2|3|4|~GG|R|F|G
AA|34567|CDEFG|89012|HIJKL|~BB||~CC|||~DD|B|C|D||~EE||||~GG||||
问题数据中的G
字段似乎没有指定正确数量的字段,或者在输入数据中缺少尾随管道。
我至少做了以下假设:
known_flds
文件中指定字段顺序。否则,我可能已经选择了要完成的文件的第一行,并按正确的字段顺序包含输出所需的所有字段。但这并不允许将字段称为必填字段。这是一个简单的剧本细分:
FNR==NR
- 解析原始文件并使用create_empty_field()
函数创建默认空字段,并按字段名称将结果放入dflts
。创建基本字段顺序,将其存储在fld_order
数组中。跳过的字段不会放入fld_order
,而是所有字段&#34;规则&#34;被添加到fld_rule
数组。fld_cnt
字段。超出known_flds
中的行数的任何字段都不会输出。opt
字段并增加j
。flds
的当前字段构建$j
变量,或者是否显示缺少字段,dflts
为空字段。flds
,但不跳过字段。这是功能细分
create_empty_field()
:
name, cnt
是来自第一个文件的参数,而fld, i
是局部变量,设置为空值以便在函数中使用。fld
设为name
($1
known_flds
)cnt
值的管道($2
来自known_flds
)。 skip_flds()
:
fnum
是记录字段编号的参数,而name
是本地变量name
$fnum
部分
fld_rule[name] == "skp"
测试跳过它。fnum
并重置name
变量。name =
和sub
调用行应该是一个新函数,但我在这里没有这样做。基本上,我在known_flds
中制作解析/转换规则,然后使用awk.script
对data
文件中的记录进行解释/强制执行。虽然这是一个合理的开始,但是当不存在manadatory字段或者是空的时,你可以另外将错误打印到另一个文件,将缺少的子字段添加到字段等等。你可能会变得如此复杂。