本周公司分配任务,将一个导入数据的任务分配给了我,要求使用sqlldr导入oracle数据库,本人是Java程序员,从来没听说过sqlldr(各位大神莫嘲笑~),在网上搜了几天,终于搞定了,一些小心得分享给大家。
需求:使用java定期定时自动将多个.csv的数据导入到一张oracle表中,处理掉里面的一些垃圾数据。
在网上搜了下sqlldr,现学现卖写了下:
ctl文件如下:
LOAD DATA
INFILE 'c:\sqlldr\data1.csv'
REPLACE INTO TABLE T_TEST
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
(A,B)
data1.csv中的数据共有3列,我只将其中两列导入到数据库中,数据库中对应的字段分别为A和B。把ctl文件放入指定的文件夹中,待启动文件使用。
注:ctl文件是指后缀是.ctl结尾的文件。
启动文件如下:
sqlldr test/test@orcl control=C:\sqlldr\sqlldr_impdata.ctl log=C:\sqlldr\sqlldr.log
启动文件会调用上面编写的ctl文件,并在文件夹里生成log日志。
注:启动文件在cmd命令行里执行。
注意!成功后指示将一个csv文件导入到了数据库中,而我们的需求是将多个csv文件导入到系统!
我的第一个想法是循环将csv文件导入到系统,但是很快我觉得这样做不现实!原因是我的需求是要由机器去导入数据,不需要人工来修来ctl文件、启动文件。
如果使用机器来模拟人工的这种方式做的,需要反复的修改ctl文件,再反复的执行启动文件,实现起来比较麻烦,故果断pass,寻找其他方案。
又在网上查了下(哈哈,总去网上查),想想可以不可以找到使用sqlldr一次性导入多个csv数据的方案,结果有点失望啊~~sqlldr不支持同时使用多个数据源导入一张数据库表的方式(至少我没有找到T_T)
比如:下面这种方式,是不支持的!!!一定注意,是不支持的!!
LOAD DATA
INFILE 'c:\sqlldr\data1.csv'
INFILE 'c:\sqlldr\data2.csv'
INFILE 'c:\sqlldr\data3.csv'
INFILE 'c:\sqlldr\data4.csv'
REPLACE INTO TABLE T_test TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
(PAYSYSBANKCODE,IBPSNAME)
不过找到了一种其他的方式来解决这个问题:既然sqlldr只支持单个文件进行导入的话,那可不可以把多个csv文件整合成一个来导入呢?
答案是可以的!
可以使用批处理的方式来处理多个csv文件,将多个csv文件整合成一个txt文件,再导入到数据库中!(⊙﹏⊙b汗,原谅我的无知吧,阿门~~我也从来没用过批处理。。。)
批处理代码如下:
for /r C:\sqlldr %%a in (*.csv) do type "%%a" >>%%~dpanewcsv.txt
注:把批处理的代码放在一个txt里面,再把后缀改成.bat文件。直接回车就可以执行了。
执行成功后生成了一个名为newcsv.txt的文件,里面包含了所有csv文件中的数据,按照我们预先约定的方式顺利导入到数据库~~当当当当~~问题出现了!!!
在以这种方式导入到数据库中的数据,有一点问题,由于我要处理掉一些垃圾数据,这些垃圾数据是由一些字母和星号***构成的,正确的数据是由数字构成的,故我要编写sql来删除掉这样的垃圾数据。
搜索不是数字的sql如下:
select * from t_test where trim(translate(A,'0123456789',' ')) is not NULL;
执行后我发现居然不好使!!这个sql是绝对没有问题的,是正确的,那么问题是出现在哪里了呢?没错,是数据的错误!
我发现导入的数据里每个数据后面都会有一串空格,我试着用trim来去掉这些空格,但是不好用,这非常奇怪,我又查看了刚才我们用批处理生成txt文件,发现这里面的数据是有问题的,每个数据后面都有空格!!
所以我采取了在导入时,使用sqlldr自带的去空格的功能,代码如下:
LOAD DATA
INFILE 'c:\sqlldr\newcsv.txt'
REPLACE INTO TABLE T_TEST
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
(A "trim(:A)",B)
但是很可惜,不好用= =#,居然自带的trim功能不好用,我开始重新审视在数据库中的数据,到底为什么不好用呢?难道数据库里存的空格,根本就不是空格?!
答案是正确的,它确实不是空格(= =#大爷的)
我使用了如下的sql如查询这一行的数据到底是什么:
select dump(t.A) from t_test t;
结果如下:
Typ=1 Len=13: 48,48,49,53,48,56,51,54,51,56,56,50,9
Typ=1 Len=13: 48,48,49,53,48,56,52,54,51,56,57,54,9
Typ=1 Len=13: 48,48,49,53,48,56,53,54,51,56,51,51,9
但是我的数据只有12位,说明最后多出来的一位就是问题所在了。
又去网上查了下。。。发现这个多出来的9,根本就不是空格,引文如下:
chr(32)是空格;
chr(8、9、10 和 13)可以分别转换为退格符、制表符、换行符和回车符。这些字符都没有图形表示,但是对于不同的应用程序,这些字符可能会影响文本的显示效果。
哈哈,原来不是正常的空格,故无论是在oracle中,还是在sqlldr中的,所有的trim功能都是无效的。。。
使用如下语句,把这个多出来的9干掉就好了:
update t_test set A = replace(A, chr(9), '');
把多出来的9换成了空,以上问题就解决了。。。这个需求真累啊,折腾了一大圈,不过有点收获还是好的^_^!
以上,可能有错误的地方,欢迎大家批评指认,毕竟我都sqlldr和批处理都没接触过,写这篇文章希望可以帮助到和我一样没接触过的人。
另,由于本人没接触过批处理,没有使用修改批处理的方案来解决问题,请大家见谅。