简单了解一下什么是SQL*Loader?有什么用?为什么要用?
SQL*Loader是Oracle数据库用于将数据从外部文件导入到 Oracle 数据库的工具。用于高性能数据加载,数据可以从任何文本文件加载,并插入到数据库。它和DB2的Load工具相似,但是提供了很多参数以供选择,支持变化的加载模式(负载格式、 选择性加载和多表荷载),可选的加载及多表加载; 它可以把一些以文本格式存放的数据顺利的导入到oracle数据库中,是一种在不同数据库之间进行数据迁移的非常方便而且通用的工具。
1)能装入不同数据类型文件及多个数据文件的数据
2)可装入固定格式,自由定界以及可度长格式的数据
3)可以装入二进制,压缩十进制数据
4)一次可对多个表装入数据
5)连接多个物理记录装到一个记录中
6)对一单记录分解再装入到表中
7)可以用 数对制定列生成唯一的KEY
8)可对磁盘或 磁带数据文件装入制表中
9)提供装入错误报告
10)可以将文件中的整型字符串,自动转成压缩十进制并装入列表中。
1:数据加载方式
1:无控制文件
SQLLoader程序主体由一个文件组成,该文件的内容要包括指定加载的数据源文件、加载数据命令、数据加载相关的控制命令和验证逻辑。但是,如果数据加载的逻辑很复杂是不建议用这种方式的,否则该文件会很庞大,而且逻辑代码变得很臃肿。这样去进行数据导入反而变的不方便。因此,无控制文件的加载方式适合于一些很简单的数据问价加载。
2:有控制文件
控制文件是用一种语言写的文本文件,这个文本文件能被SQLLOADER识别。SQL*LOADER根据控制文件可以找到需要加载的数据。并且分析和解释这些数据,控制文件由三个部分组成:
1):全局选件,行,跳过的记录数等;
2):INFILE子句指定的输入数据;
3):数据特性说明。
2:数据传输流程以及对应的各种文件信息
一般第二种方式更实用,因为设计灵活,模板和数据分离
从图中可以看出,把Data_Source和Ctl_File传入SQLLoader,输出的结果包括日志,坏文件(错误的文件),丢弃文件(被拒绝的记录)和导入成功的数据四部分。
1:参数文件(可选):
可以把参数直接写在控制文件里,也可以单独写一个参数文件。(参数文件的意义:如果有多个导入程序而且他们部分参数都相同时,可以不必重复的在各个程序中都输入相同的参数,定义成参数文件调用即可,参数文件的调用方法:在控制文件的OPTIONS字句里调用,但是,控制文件中命令行参数的优先级最高,可以覆盖参数文件里的参数配置)
2:数据文件:
对于 SQLLoader, 除控制文件外就是输入数据。SQLLoader可从一个或多个指定的文件中读出数据。如果 数据是在控制文件中指定,就要在控制文件中写成 INFILE * 格式。当数据固定的格式(长度一样)时且是在文件中得到时,要用INFILE “fix n”
3:坏文件:
坏文件包含那些被SQLLoader拒绝的记录。被拒绝的记录可能是不符合要求的记录。
坏文件的名字由 SQLLoader命令的BADFILE 参数来给定
4:丢弃文件(可选)(Discard File):
有些数据,虽然数据格式、数据类型没有问题,但它被逻辑条件过滤掉了(由控制文件WHEN设置),会被放入丢失文件。
5:日志文件及日志信息:
当SQLLoader 开始执行后,它就自动建立 日志文件。日志文件包含有加载的总结,加载中的错误信息等。
1:命令
SQLLoader可以在Windows系统下使用,也可以在Unix系统下使用,大同小异
sqlldr/sqlload keyword=value[,keyword=value,…]
如果忘记了某些参数的含义时,也可以通过这个方式快速查询:
输入sqlldr,后面不接任何参数,将显示所有的命令行参数的简单描述及其默认值
2:程序参数
Sqlldr命令参数组要有以下:
Userid:装载使用到的帐号信息,包括数据库信息,格式如:userid=user/passwd@dbname
Control:指定装载使用到的控制文件
Log:指定装载使用到的日志文件
Bad:指定装载使用到的BAD文件
Data:指定装载使用到的数据文件,如果在控制文件中也制定infile文件,那么将优先使用命 令行的data文件,control文件中的第一个infile文件将忽略,如果control文件中只有一个data文件那么sqlldr将给出一个警告。
Discard :discard 文件,不符合转载条件的记录文件
Discardmax;允许discards 数目,默认是全部
Skip;跳过记录数
Load:指定装载数据的逻辑数目,默认是说有记录。
注:逻辑记录和物理记录的区别:逻辑记录是指导入数据库的记录,物理记录数指文 件中存在的记录。一般情况下逻辑记录跟物理记录相等,但是有些情况下,如,多条 物理记录联合装载,这样可能出现不相等的情况。
Errors:允许出错数目,如果达到出错数就退出装载,默认50
Rows:装载提交数目,普通装载默认64,在直接路径如果没有指定默认为全部记录,通过这个特性可以用来控制sqlldr的事务一致性。
Bindsize:指定普通转载绑定数组的值,默认256000,该值之适用于普通装载,而不适用于直接路径装载,因为直接路径装载使用的是直接路径API,而不是普通装载的insert。设置大的bindsize可以提供每次insert的记录数目。
Silent:提示在装载时候终端上显示的内容,有以下几种可以选择。
Header:禁止sqlldr装载标题提示信息,但在log文件依然出现。
Feedback:禁止"commit point reached"提示信息。
Errors:禁止数据错误信息写在log日志文件,但是rejected records依然会写入。
Discards:禁止在log日志里面的记录信息写入discard文件。
Partitions:在采用直接路径装载的时候,取消写每个分区统计信息入日志文件。
ALL:包含以上所有的值
Direct:使用直接路径装载
Parfile:参数文件指定。
Parallel:并行装载,默认为FALSE,只能用于direct装载方式。
File:指定装载过程中使用的数据库中的数据文件,该选项只适用于并行装载,通过该选项可以提高磁盘的读写速度。不同的装载可以存放不同的数据库文件。
skip_unusable_indexes:该值跟数据库配置文件中的skip_unusable_indexes类似,在装载过程中遇到无效索引的时候,不停下来继续进行装载。
skip_index_maintenance:停止索引的维护,在直接路径转载的时候。使用该选项将插入一个没用的索引键值代替把索引制成无效。这样不会因为前面的转载使索引无效而影响后面的装载。默认为FALSE。
commit_discontinued:提交已经装载的行数,如果装载失败的时候。默认为FALSE。
Readsize:该参数用于设置读取数据的大小,如果读控制文件中的值就使用64K大小不变的值,readsize默认值为1048576,最大可设置的值为20M,在普通装载的情况下, bindsize的大小受限制与readsise的设置,如果readsize的值小于bindsize的值, sqlldr将会自动让readsize等于bindsize的值。
external_table:使用sqlldr来使用外部表的功能; 本选项提供三个可选项:
NOT_USED:默认为不使用外部表装载功能
GENERATE_ONLY:通过该选项可以生成需要通过外部表装载的所有步骤
EXECUTE:直接使用外部表功能装载(具体说明参见外部表装载)
Columnarrayrows:该选项适用于direct路径装载,默认为5000。该选项sqlldr将不做技术,如果使用该选项则需要用户设置正确,或者接受默认的值。
Streamsize:该选项为直接路径装载所用,需要跟columnarrayrows配对使用。
multithreading :在多cpu的系统中默认为TRUE,在单cpu的系统中默认为FALSE。使用多线程装载在direct path的情况下。推荐使用FALSE,因为在对于大数 据量的转载中,可能出现中途挂起的情况。
Resumable:设定可恢复的空间分配,默认为FALSE。通过该选项可以用于转载过程中空间不足引起的错误。
resumable_name:该值定义空间使用的语句。默认
‘User USERNAME (USERID), Session SESSIONID, Instance INSTANCEID’
resumable_timeout:空间处理时间,默认7200秒。如果在这个时间内没有处理好空间,那 么sqlldr将因为空间不足,而错误退出。该选项需要首先设resumable为TRUE。
date_cache:用于数据转化的临时空间 默认是1000。本选项只能用于direct路径装载。在需要数据转化,如date,timestamp类新装载上可以使用,当然如果转换的数据唯 一性很高,可能就很难有作用,对于很多重复的需要转换的比较有用,可以大大提高转化的时间。
qlldr的命令行参数可以直接放在命令行,也可以放在控制文件,也可以直接放在参数文件PARFILE (parameter file)里面。
注意:在重复指定的参数里面,命令行的参数凌驾于任何写在参数文件和控制参数文件之上的参数。
注意:
在SQLLoader命令中,有两种方式可以指定命令行参数:通过位置或者通过关键字。通过位置的例子:‘sqlldr scott/tiger test.ctl’,
通过关键字的例子:‘sqlldr userid=scott/tiger control=test log=test.log’;但是不要前面使用关键字指定后面通过位置制定的混合方式;为清楚起见最好所有命令行参数都用关键字指定。
1:控制文件语法
控制文件是SQL*Loader里最重要的文件,它定义数据文件的位置、数据的格式、以及配置数据加载过程的行为。所有的命令行参数都可以在控制文件里配置
控制文件的格式如下:
OPTIONS ( { [SKIP=integer] [ LOAD = integer ]
[ERRORS = integer] [ROWS=integer]
[BINDSIZE=integer] [SILENT=(ALL|FEEDBACK|ERROR|DISCARD) ] )
LOAD[DATA]
[ { INFILE | INDDN } {file | * }
[STREAM | RECORD | FIXED length [BLOCKSIZE size]|
VARIABLE [length] ]
[ { BADFILE | BADDN } file ]
{DISCARDS | DISCARDMAX} integr ]
[ {INDDN | INFILE} . . . ]
[ APPEND | REPLACE | INSERT ]
[RECLENT integer]
[ { CONCATENATE integer |
CONTINUEIF { [THIS | NEXT] (start[: end])LAST }
Operator { 'string' | X 'hex' } } ]
INTO TABLE [user.]table
[APPEND | REPLACE|INSERT]
[WHEN condition [AND condition]...]
[FIELDS [delimiter] ]
(
column {
RECNUM | CONSTANT value |
SEQUENCE ( { integer | MAX |COUNT} [, increment] ) |
[POSITION ( { start [end] | * [ + integer] }
) ]
datatype
[TERMINATED [ BY ] {WHITESPACE| [X] 'character' } ]
[ [OPTIONALLY] ENCLOSE[BY] [X]'charcter']
[NULLIF condition ]
[DEFAULTIF condotion]
}
[ ,...]
)
[INTO TABLE...][BEGINDATA]
2:命令解释&参数释义
1)要加载的数据文件:
1:INFILE 和INDDN是同义词,它们后面都是要加载的数据文件。如果用 * 则表示数据就在控制文件内。在INFILE 后可以跟几个文件。
2:STRAM 表示一次读一个字节的数据。新行代表新物理记录(逻辑记录可由几个物理记录组成)。
3.RECORD 使用宿主操作系统文件及记录管理系统。如果数据在控制文件中则使用这种方法。
3:FIXED length 要读的记录长度为length字节,
4: VARIABLE 被读的记录中前两个字节包含的长度,length 记录可能的长度。缺伤为8k字节。
5:BADFILE和BADDN同义。Oracle 不能加载数据到数据库的那些记录。
6:DISCARDFILE和DISCARDDN是同义词。记录没有通过的数据。
7:DISCARDS和DISCARDMAX是同义词。Integer 为最大放弃的文件个数。
2)加载的方法:
1:APPEND 给表添加行。
2:INSERT 给空表增加行(如果表中有记录则退出)。
3:REPLACE 先清空表在加载数据。
4:RECLEN 用于两种情况,1)SQLLDR不能自动计算记录长度,2)或用户想看坏文件的完整记录时。对于后一种,Oracle只能按常规把坏记录部分写到错误的地方。如果看整条记录,则可以将整条记录写到坏文件中。
3)指定最大的记录长度:
1: CONCATENATE 允许用户设定一个整数,表示要组合逻辑记录的数目。
4)建立逻辑记录:
1:THIS 检查当前记录条件,如果为真则连接下一个记录。
2:NEXT 检查下一个记录条件。如果为真,则连接下一个记录到当前记录来。
3:Start: end 表示要检查在THIS或NEXT字串是否存在继续串的列,以确定是否进行连接。如:continueif next(1-3)=‘WAG’ 或continueif next(1-3)=X’0d03if’
5)指定要加载的表:
1:INTO TABLE 要加的表名。
2:WHEN 和select WHERE类似。用来检查记录的情况,如:when(3-5)=‘SSM’ and (22)=’*"
6)介绍并括起记录中的字段:
1:FIELDS给出记录中字段的分隔符,FIELDS格式为:
FIELDS [TERMIALED [BY] {WHITESPACE | [X] ‘charcter’} ]
[ [ OPTIONALLY] ENCLOSE [BY] [X]‘charcter’ ]
TERMINATED 读完前一个字段即开始读下一个字段直到介绍。
WHITESPACE 是指结束符是空格的意思。包括空格、Tab、换行符、换页符及回车符。如果是要判断但字符,可以用单引号括起,如X’1B’等。
OPTIONALLY ENCLOSED 表示数据应由特殊字符括起来。也可以括在TERMINATED字符内。使用OPTIONALLY要同时用TERMINLATED。
ENCLOSED 指两个分界符内的数据。如果同时用 ENCLOSED和TERMINAED ,则它们的顺序决定计算的顺序。
7)定义列:
column 是表列名。列的取值可以是:
BECHUM 表示逻辑记录数。第一个记录为1,第2个记录为2。
CONSTANT 表示赋予常数。
SEQUENCE 表示序列可以从任意序号开始,格式为:
SEQUENCE ( { integer | MAX |COUNT} [,increment]
POSITION 给出列在逻辑记录中的位置。可以是绝对的,或相对前一列的值。格式为:
POSITION ( {start[end] | * [+integer] } )
Start 开始位置
下面通过一个简单的案例大致讲解一些SQL loader的用法
通过一个简单的数据导入案例解释一下SQL Loader的开发方式,此处讲解的是有控制文件方法。
1:业务需求
由于这边需要导入大量的货位信息,直接使用for update的方式非常的慢,所以使用SQL loader的方式将excel的数据导入数据库中已有的通用临时表中
2:实现方法
1:根据excel文件生成对应的CSV文件
命令解释:
1)开始初始化参数
OPTIONS(skip=1,BINDSIZE=111620) 是可选的参数列表
skip = 1:要跳过的逻辑记录的数量(csv文件第一行是表头,调过一行不导入表头)
BINDSIZE=111620 : 每次提交记录的缓冲区的大小是 111620 字节
2)开始加载数据
load data :表示开始加载数据
infile ‘&1’ :读取文件,此处&1是接收并发程序传入的第一个参数,因为我在请求
的参数设置了文件的路径和文件名
badfile data.bad :表示坏文件存放的文件名
discardfile data.dsc :丢弃文件写入的文件名
3)选择加载数据模式(以下是四种数据加载模式)
APPEND 原先的表有数据 就加在后面——也正是此处所选模式
4)导入数据库目标表
into table cux_glo_import_temp 表示导入的目标Table是:cux_oa_weeks_iface
5)如何分割(列与列分隔符)
fields terminated by “,” optionally enclosed by ‘"’ 以逗号分割,类内容可包含双引号
6)表的column列表
就这样,没几行代码,就可以完成一份外围系统的数据导入,很轻便的就开发好了一个接口程序。
3:注册可执行和并发请求
默认的文件路径:/u01/test/apps/fs1/EBSapps/appl/cux/12.0.0/data/CUXWMSTEMP.csv
可根据自己的实际情况进行定义即可。
1:业务需求
在我们平时开发的过程中,其实会遇到不同的类型的文件需要导入,其实按照之前的单个导入也可以推演出,多文件导入也是可行的,具体细节不做多赘述,简单介绍下控制文件的写法即可。
2:控制文件写法
OPTIONS (SKIP=2,BINDSIZE=100000, SILENT=(ERRORS,FEEDBACK))
LOAD DATA
INFILE * --第一个数据文件(数据源位于控制文件本身内)
INFILE --第二个数据文件
'/u01/test/apps/fs1/EBSapps/appl/cux/12.0.0/data/CUXWMSTEMP01.csv'
INFILE --第三个数据文件
'/u01/test/apps/fs1/EBSapps/appl/cux/12.0.0/data/CUXWMSTEMP02.csv'
BADFILE CUXWMSTEMP.bad
DISCARDFILE CUXWMSTEMP.dsc
APPEND
INTO TABLE APPS.CUX_FND_UNIVERSAL_TMP
replace --全表清空的方式导入(先清空表再导入)
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
TRAILING NULLCOLS(
OBJECT_CHAR1,
OBJECT_CHAR2,
OBJECT_CHAR3,
OBJECT_CHAR4,
OBJECT_CHAR5,
OBJECT_CHAR6,
OBJECT_CHAR7,
OBJECT_CHAR8
)
在之前只是做了执行方法为 SQL LOADER的案例,虽然也可以实现数据导入,但是局限性比较大,比如我一个请求想实现多种文件格式的数据导入,单纯用之前的方法就无法满足需求,所以现在补充一个新方法:主机程序(HOST)和SQL Loader的结合使用,方便我们可以用一个请求可以实现调用不同格式的CTL文件的方法
1:注册主机并发程序
主机程序的注册与之前的SQL Loader以及并发请求的注册都是很类似的,只不过是执行方法不同而已
参数设置:
为了能实现调用不同的CTL文件和数据文件,所以作为参数把想要的数据直接输入即可,我把文件的后缀也加进去,如果不想输入参数时带后缀,则需要在主机程序中进行处理和拼接即可(此处为了方便,我直接把CTL文件和数据文件都放在同一个路径下,可根据自己需要和规范,自己更换路径即可)
2:开发主机程序(重点部分)
想让主机程序能使用运行起来,则需要写主机调用的文件,文件的名称为:执行文件名.prog(至于后缀是否必须为prog尚未研究),我是直接在TXT中写的代码,然后直接改的后缀的。
最好是UNIX的格式,防止Windows格式的出现识别不了的情况
完整案例代码:
#!/bin/ksh
###################################################
#Shell Name : CUXSQLLOADERDEMO.prog
#Parameters : NONE
#Purpose This shell put the created files to ftp server
#history: 2018-11-29 yuhu.ye
###################################################
ORA_USER_PASS="$1"
USERID="$2"
USERNAME="$3"
REQUESTID="$4"
CTL_NAME="$5"
CTL_DIR="$6"
FTP_NAME="$7"
FTP_DIR="$8"
l_dir="/home/UAT/app/fs1/EBSapps/appl/cux/12.0.0/log"
l_bad_flie=$l_dir/$REQUESTID.bad
l_log_file=$l_dir/$REQUESTID.log
#输出参数信息信息
put ()
{
echo "开始输出参数信息信息"
echo $ORA_USER_PASS
echo $USERID
echo $USERNAME
echo $REQUESTID
echo $CTL_NAME
echo $CTL_DIR
echo $FTP_NAME
echo $FTP_DIR
echo "输出参数信息信息结束"
}
#验证路径是否存在
validate_data ()
{
echo "验证是否存在CTL文件"
if [ ! -f "$CTL_DIR/$CTL_NAME" ]
then
echo "CTL文件路径不存在"
exit 1
else
echo "CTL文件路径存在"
fi
echo "验证CTL文件的是否空"
if [ ! -s "$CTL_DIR/$CTL_NAME" ]
then
echo "CTL文件内容为空"
exit 1
else
echo "CTL 文件不为空"
fi
echo "验证CTL文件是否可读"
if [ ! -r "$CTL_DIR/$CTL_NAME" ]
then
echo "CTL文件内容不可读"
exit 1
else
echo "CTL 文件内容可读"
fi
echo "验证是否存在FILE文件"
if [ ! -f "$FTP_DIR/$FTP_NAME" ]
then
echo "FILE文件路径不存在"
exit 1
else
echo "FILE文件路径存在"
fi
echo "验证FILE文件的是否空"
if [ ! -s "$FTP_DIR/$FTP_NAME" ]
then
echo "FILE文件内容为空"
exit 1
else
echo "FILE文件不为空"
fi
echo "验证FILE文件是否可读"
if [ ! -r "$CTL_DIR/$CTL_NAME" ]
then
echo "FILE文件内容b不可读"
exit 1
else
echo "FILE文件内容可读"
fi
}
#导入数据
laod_data ()
{
echo "导入数据"
#sqlldr userid=ORA_USER_PASS control=$CTL_DIR/$CTL_NAME data=$FTP_DIR/$FTP_NAME
sqlldr $FCP_LOGIN silent=feedback control=$CTL_DIR/$CTL_NAME data=$FTP_DIR/$FTP_NAME bad=$l_bad_flie log=$l_log_file
if [ -f "$l_bad_flie" ]
then
echo "SQL Loader 失败:"$l_bad_flie
exit 1
fi
if [ -f "$l_log_file" ]
then
echo "SQL Loader 日志文件"$l_log_file
else
echo "未发现日志文件"
exit 1
fi
}
#主函数
main ()
{
put
validate_data
laod_data
}
main
代码讲解:
1:主机程序会先进入MAIN函数中运行
2:主机程序的前四个参数是系统默认的,不允许修改,自己要添加参数可以从第五个开始
#系统默认参数
ORA_USER_PASS="$1" 含义:数据库的账户密码信息 APPS/apps
USERID="$2" 含义:系统用户的ID,如1110
USERNAME="$3" 含义:系统用户名,HAND_WMS
REQUESTID="$4" 含义:系统请求ID
#客户化添加参数
CTL_NAME="$5" 含义:CTL的文件名(带后缀)
CTL_DIR="$6" 含义:CTL文件的路径
FTP_NAME="$7" 含义:数据文件的名称 (.csv)
FTP_DIR="$8" 含义:数据文件的路径
Linux文件命令参考(特别需要注意空格,不然很容易出现错误)
操作符 | 说明 | 举例 |
---|---|---|
-b file | 检测文件是否是块设备文件,如果是,则返回 true | [ -b $file ] 返回 false |
-c file | 检测文件是否是字符设备文件,如果是,则返回 true | [ -c $file ] 返回 false |
-d file | 检测文件是否是目录,如果是,则返回 true | [ -d $file ] 返回 false |
-f file | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true | [ -f $file ] 返回 true |
-g file | 检测文件是否设置了 SGID 位,如果是,则返回 true | [ -g $file ] 返回 false |
-k file | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true | [ -k $file ] 返回 false |
-p file | 检测文件是否是有名管道,如果是,则返回 true | [ -p $file ] 返回 false |
-u file | 检测文件是否设置了 SUID 位,如果是,则返回 true | [ -u $file ] 返回 false |
-r file | 检测文件是否可读,如果是,则返回 true | [ -r $file ] 返回 true |
-w file | 检测文件是否可写,如果是,则返回 true | [ -w $file ] 返回 true |
-x file | 检测文件是否可执行,如果是,则返回 true | [ -x $file ] 返回 true |
-s file | 检测文件是否为空(文件大小是否大于0),不为空返回 true | [ -s $file ] 返回 true |
-e file | 检测文件(包括目录)是否存在,如果是,则返回 true | [ -e $file ] 返回 true |
3:上传prog文件和授权
将写好的prog文件上传到$CUX_TOP/bin下,(因为我注册主机程序的时候用的客户化应用)
授权:
chmod 777 CUXSQLLOADERDEMO.prog
或者手工直接改
4:创建文件和主机程序的连接
命令:
ln -s $FND_TOP/bin/fndcpesr $CUX_TOP/bin/CUXSQLLOADERDEMO
这样CUXSQLLOADERDEMO脚本就可以接受并发请求传进去的参数。