最近梳理系统功能的时候发现如今每月处理完数据以后,须要给别的系统传送批接口文件,接口文件的内容是来自于Oracle数据表中的数据。我每次都须要手工执行一下存储过程,让数据从正式表中插入到接口表中,而后再借助plsql工具软件sqlplus的spool工具导出接口文件,而后把导出来的7个接口文件,打成zip压缩包,再经过前台系统实现上传(这一部分功能以前已经在前台系统实现部署上线了,详细可参见博文:https://www.cnblogs.com/zhong...)。可是如今每月都须要作这样的事情,很繁琐,并且每月都须要耗费个人精力,程序猿的个性喜欢探索、创造、和解决问题,本着这样的态度,我开始了这件事的优化之旅。html
针对于此需求,大概有两种方案。sql
方案一:把这一系列的操做都写在Java后台的业务逻辑当中,而后经过前台系统每个月传参数过去,实现调用。shell
方案二:能够用shell脚本实现存储过程的调用和数据接口文件的导出和压缩。windows
因为系统是一个老系统,各类技术框架个分层并无那么明显,并且有7个文件之多,用Java写起来不管是业务逻辑仍是代码量都是及其多,并且不方便测试和调试。相比之下,用shell脚本写,逻辑变得清晰明了,导出的接口文件写在sql文件中,用sqlplus去执行它即可。所以我选用了方案二。框架
第一步:细化业务逻辑,第一步就是须要去调用一个存储过程,存储过程的主要做用是把正式表中当月的数据插入到接口表中。这一步很简单,代码以下工具
sqlplus zh/dbpassword@zh10g << sql declare imonth varchar2(6); strrtn varchar2(8); countnum NUMBER; begin select to_char(add_months(sysdate,-1),'YYYYMM') into imonth from dual; SELECT count(*) INTO countnum FROM t_report_if_carrier WHERE bill_cycle=imonth; IF (countnum=0) THEN Dbms_Output.put_line(imonth+':'+countnum); PR_REPORT_IF(imonth,strrtn); END IF; end; / sql
计算出当月的上一个月是多少,而后判断表中有没有该月的数据,若是没有,则认为没有执行该存储过程,须要执行存储过程测试
第二步:须要对导出文件的目录作一下清理,若是上次导出过了,则删除再从新到导出,代码以下:优化
cd /workforzhongfs/jffile/ rm -rf $report_month mkdir $report_month cd $report_month
第三步:把须要执行导出的语句放到一个spoll_file.sql文件中,而后经过sqlplus调用$report_month 表明着须要传给脚本的当前月的上一个月的参数,如如今是2019年04月,则参数为201903spa
sqlplus zh/dbpassword@zh10g @/workforzhongfs/spoll_file.sql $report_month
spoll_file.sql的内容以下,其中&1表明$report_month传过来的月份参数。调试
SET NEWPAGE 0 SET SPACE 0 SET LINESIZE 2500 SET PAGESIZE 0 SET ECHO OFF SET FEEDBACK OFF SET VERIFY OFF SET HEADING OFF SET MARKUP HTML OFF SPOOL OFF SET COLSEP ' ' SET TRIMSPOOL ON SET TERMOUT OFF COL report_name FORMAT a35 COL report_name NEW_VALUE rpt_name select 'CMBFYDWAL06002A'||&1||'0000000.000' as report_name from dual; SPOOL &rpt_name select bank_warrant_no || CHR(9)|| rec_pay_date || CHR(9)|| bank_name || CHR(9)|| record_flag || CHR(9)|| carrier_name || CHR(9)|| carrier_id || CHR(9)|| descript || CHR(9)|| amount_bill || CHR(9)|| exchange_name2 || CHR(9)|| rate_bill || CHR(9)|| amount || CHR(9)|| exchange_name || CHR(9)|| rate || CHR(9)|| amount_rmb || CHR(9)|| bank_fee || CHR(9)|| remark || CHR(9)|| bill_cycle || CHR(9)|| erp_def_code as data from t_report_if_recpay a WHERE 1 = 1 and bill_cycle=&1 order by erp_def_code asc; SPOOL OFF select 'CMBFYDWAL06005A'||&1||'0000000.000' as report_name from dual; SPOOL &rpt_name select ADVANCE_NO || CHR(9)|| carrier_name || CHR(9)|| WARRANT_NO || CHR(9)|| REC_DATE || CHR(9)|| EXCHANGE_NAME || CHR(9)|| AMOUNT || CHR(9)|| AMOUNT_RMB || CHR(9)|| BALANCE || CHR(9)|| BALANCE_RMB as data from t_report_if_advance WHERE 1 = 1 and bill_cycle=&1 order by erp_def_code asc; SPOOL OFF select 'CMBFYDWAL06006A'||&1||'0000000.000' as report_name from dual; SPOOL &rpt_name select BAIL_NO || CHR(9)|| carrier_name || CHR(9)|| warrant_no || CHR(9)|| REC_DATE || CHR(9)|| EXCHANGE_NAME || CHR(9)|| AMOUNT || CHR(9)|| AMOUNT_RMB || CHR(9)|| BALANCE || CHR(9)|| BALANCE_RMB || CHR(9)|| bill_cycle || CHR(9)|| erp_def_code as data from t_report_if_bail WHERE 1 = 1 and bill_cycle=&1 order by erp_def_code asc; SPOOL OFF select 'CMBFYDWAL06007A'||&1||'0000000.000' as report_name from dual; SPOOL &rpt_name select report_month || CHR(9)|| center || CHR(9)|| period || CHR(9)|| types || CHR(9)|| property || CHR(9)|| carrier_name || CHR(9)|| customer_number || CHR(9)|| currency || CHR(9)|| duration || CHR(9)|| amount || CHR(9)|| basiccurrency || CHR(9)|| reference_no || CHR(9)|| bill_cycle || CHR(9)|| erp_def_code as data from t_report_if_rp WHERE 1 = 1 and bill_cycle=&1 order by erp_def_code asc; SPOOL OFF select 'CMBFYDWAL01001A'||&1||'0000000.000' as report_name from dual; SPOOL &rpt_name select DATA_TYPE|| CHR(9) ||CHINESENAME|| CHR(9) || CARRIER_NAME|| CHR(9) ||CARRIER_ID|| CHR(9) ||ACCOUNT_CODE|| CHR(9) || ACCOUNT_NAME|| CHR(9) ||CONTACT_PERSON|| CHR(9) || TELEPHONE_NO|| CHR(9) ||EMAIL_ADDRESS|| CHR(9) || BENEFICIARY_NAME|| CHR(9) ||ACCO_LINKMAN_PHONE|| CHR(9) || ACCO_LINKMAN_EMAIL|| CHR(9) ||BUSI_MANA_NAME|| CHR(9) || ACCO_MANA_NAME as data from t_report_if_carrier WHERE 1 = 1 and bill_cycle=&1 order by erp_def_code asc; SPOOL OFF select 'CMBFYDWAL06004A'||&1||'0000000.000' as report_name from dual; SPOOL &rpt_name select carrier_name || CHR(9)|| destroybill_no || CHR(9)|| settle_flag || CHR(9)|| service_name || CHR(9)|| load_date || CHR(9)|| jfdate || CHR(9)|| settdate || CHR(9)|| exchange_name || CHR(9)|| settle_amount || CHR(9)|| settle_amount_new || CHR(9)|| bill_cycle || CHR(9)|| erp_def_code as data From t_report_if_destroys WHERE 1 = 1 and bill_cycle=&1 order by erp_def_code asc; SPOOL OFF select 'CMBFYDWAL06001A'||&1||'0000000.000' as report_name from dual; SPOOL &rpt_name select carrier_name || CHR(9)|| carrier_no || CHR(9)|| center_name || CHR(9)|| destroybill_no || CHR(9)|| rec_pay || CHR(9)|| buy_property || CHR(9)|| service_no || CHR(9)|| map_name || CHR(9)|| load_date || CHR(9)|| jfdate || CHR(9)|| settdate || CHR(9)|| end_date || CHR(9)|| exchange_name || CHR(9)|| settle_amount || CHR(9)|| settle_amount_rmb || CHR(9)|| current_amount || CHR(9)|| amount_30 || CHR(9)|| amount_90 || CHR(9)|| amount_180 || CHR(9)|| amount_360 || CHR(9)|| AMOUNT_720 || CHR(9)|| AMOUNT_1080 || CHR(9)|| AMOUNT_1440 || CHR(9)|| AMOUNT_1800 as data From t_report_if_datadetail WHERE 1 = 1 and bill_cycle=&1 order by erp_def_code asc; SPOOL OFF QUIT
问题一:本来觉得这样问题就能够获得解决了,万万没想到,spool导出的文件换行符出现了问题,Windows下的换行符是“\r\n”,而Linux的则是“\n”,这样致使看起来的文件内容是同样的实则是不同的,用MD5校验以后发现两者不一致。
问题二:导出的CMBFYDWAL01001A2019030000000.000文件每一行的行末有大量的空格,而在windows下用plsql软件导出来的该接口文件没有这个问题。
在网上变换各类搜索关键词和不断地试验测试,最终问题都获得解决
问题二的解决,用sed把行末的空格替换成空,
sed 's/[[:space:]][[:space:]]*$//g' $file>$file-sed
问题一的解决,这样子就能够把换行符从Linux的替换为Windows下的换行符。
awk '{ print $0"\r" }'<$file-sed > $file-fs
写了一个循环,当前目录下的全部文件均可以获得替换。
for file in CMBFY* do sed 's/[[:space:]][[:space:]]*$//g' $file>$file-sed awk '{ print $0"\r" }'<$file-sed > $file-fs echo $file >> $report_month.log done
解决了上述的问题,那么还遇到什么问题呢?
我把这个脚本 加到crontab中执行的时候,发现脚本开始须要制定月份参数,这样子不又回到了原点么?所以,我必需要解决这个问题。我在网上搜索,大多数人都告诉我用“date -d”能够计算上月的月份,可是个人程序是部署在AIX中的,AIX没有这些奇奇怪怪的选项,采起了个折中的办法,以下代码
month=`date +%m |sed 's/$/b12a01a02a03a04a05a06a07a08a09a10a11a12/; s/^\(..\)b.*\(..\)a\1.*/\2/'` year=`date +%Y` report_month="$year$month"
这样便能计算出上一个月(虽然我也不太知道原理),如下为测试截图
最后加到crontab中即可以自动执行了
万事大吉,愿世界没有bug。