無意中在網(wǎng)上看到一篇文章《利用kettle中的JS來完成ETL數(shù)據(jù)校驗(yàn)》对竣,挺受啟發(fā)的派歌,覺得用JS來實(shí)現(xiàn)ETL的自動(dòng)化校驗(yàn),是個(gè)不錯(cuò)的思路潘明。但是這篇文章里給的JS腳本樣例確實(shí)有待改進(jìn)辐棒,一是讓初學(xué)者看著不那么清晰病曾,二是擴(kuò)展性和維護(hù)性都較差姊途。于是我做了二次改造,重新編寫了腳本知态,如下:
//Script here
var strConn = "TestOrcl";
var check_status=0;//如果檢測(cè)到有任何一種校驗(yàn)錯(cuò)誤,則check_status=1
var check_table="E_OT_PRMTALT";//校驗(yàn)有關(guān)的表名字
var check_table_id="LICALTID";//校驗(yàn)表主鍵
var check_name=LICALTID;//校驗(yàn)表主鍵值
var check_detail="";//校驗(yàn)到的錯(cuò)誤詳細(xì)情況
var check_type="";//校驗(yàn)到的錯(cuò)誤類型
var check_date=new Date();//校驗(yàn)時(shí)間
var source_table="E_OT_PRMTALT";//數(shù)據(jù)源表名稱立叛,如果數(shù)據(jù)來自多個(gè)數(shù)據(jù)表负敏,則需要聲明多個(gè)
var source_table_id="LICALTID";//數(shù)據(jù)源表主鍵,如果多個(gè)表聯(lián)合主鍵秘蛇,則需要聲明多個(gè)主鍵
/////////////////////////////字段唯一性校驗(yàn)//////////////////////////////////////////
var isuniqueArray=new Array("LICALTID","LICID");//一維數(shù)組其做,表的字段名
var isunique_str="";
var isunique_column="";
for(var i=0;i<isuniqueArray.length;i++){
//1:唯一性枚舉值
? isunique_str+="var "+isuniqueArray[i]+"_isunique=0;";
? //唯一性校驗(yàn)枚舉值賦值
? isunique_str+="var uniquesql_"+isuniqueArray[i]+"=\"SELECT count(1) FROM "+check_table+" where "+isuniqueArray[i]+"='\"+"+isuniqueArray[i]+"+\"' \";";
? isunique_str+="if(fireToDB(strConn,uniquesql_"+isuniqueArray[i]+")[0][0]==1){"+isuniqueArray[i]+"_isunique=1;}";
? //校驗(yàn)所有表需要校驗(yàn)的字段,如果有一個(gè)校驗(yàn)失敗赁还,則校驗(yàn)狀態(tài)為1
? isunique_str+="if(check_status==0){if("+isuniqueArray[i]+"_isunique==0)check_status=1;}";
? //check is unique? return not unique column
? isunique_str+="if("+isuniqueArray[i]+"_isunique==0){if(isunique_column==\"\"){ isunique_column = \""+ isuniqueArray[i] +"\";}else{isunique_column+=\"妖泄、\"+\""+isuniqueArray[i]+"\";}}";?
}
//最終輸出的錯(cuò)誤詳細(xì)情況
isunique_str+="if(check_status==1){check_type=\"違反唯一規(guī)則\";check_detail=\"表\"+source_table+\"中,字段\"+isunique_column+\"違反了唯一規(guī)則\";}";
eval(isunique_str);
//////////////////////////////////////////////////////////////////////////////////
/////////////////////////////字段非空校驗(yàn)//////////////////////////////////////////
var isnullArray=new Array("ALT","ALTBE","ALTAF","ALTDATE");//一維數(shù)組艘策,表的字段名
var isnull_str="";
var isnull_column="";
check_status=0;//校驗(yàn)狀態(tài)置0
for(var i=0;i<isnullArray.length;i++){
//2:非空枚舉值
isnull_str+="var "+isnullArray[i]+"_isnull=0;";
//非空校驗(yàn)枚舉值賦值
isnull_str+="if("+isnullArray[i]+"==null||"+isnullArray[i]+"==\"\"){"+isnullArray[i]+"_isnull=1;}";
//校驗(yàn)所有表需要校驗(yàn)的字段蹈胡,如果有一個(gè)校驗(yàn)失敗,則校驗(yàn)狀態(tài)為1
isnull_str+="if(check_status==0){if("+isnullArray[i]+"_isnull==1)check_status=1;}";
//check is null? return null column
isnull_str += "if("+isnullArray[i]+"_isnull==1){if(isnull_column==\"\"){isnull_column = \""+ isnullArray[i] +"\";}else{isnull_column+=\"朋蔫、\"+\""+isnullArray[i]+"\";}}";
}
//最終輸出的錯(cuò)誤詳細(xì)情況
isnull_str+="if(check_status==1){if(check_detail==\"\"){check_type=\"違反非空規(guī)則\";check_detail=\"字段\"+ isnull_column +\"違反了非空規(guī)則\";}else{check_type+=\",\"+\"違反非空規(guī)則\";check_detail+=\",字段\"+ isnull_column +\"違反了非空規(guī)則\";}}";
eval(isnull_str);
//////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////標(biāo)準(zhǔn)值校驗(yàn)//////////////////////////////////////////
var isnormalArray = [["S_EXT_FROMNODE","in ('220000')"],["ALT","in ('許可文件編號(hào)','許可文件名稱','許可機(jī)關(guān)','許可內(nèi)容')"]];//二維數(shù)組罚渐,第一列為字段,第二列為匹配規(guī)則
var isnormal_str="";
var isnormal_column="";
check_status=0;//校驗(yàn)狀態(tài)置0
for(var i=0;i<isnormalArray.length;i++){
//3:標(biāo)準(zhǔn)化枚舉值
isnormal_str+="var "+isnormalArray[i][0]+"_isnormal=0;";
//標(biāo)準(zhǔn)化校驗(yàn)枚舉值賦值
isnormal_str+="var normalsql_"+isnormalArray[i][0]+"= \"select? count(1) from "+check_table+" where "+ isnormalArray[i][0] +" "+isnormalArray[i][1]+" and "+check_table_id+"='"+check_name+"'\";";
isnormal_str+="if(fireToDB(strConn, normalsql_"+isnormalArray[i][0]+")[0][0]>0){"+ isnormalArray[i][0] +"_isnormal=1;}";
//校驗(yàn)所有表需要校驗(yàn)的字段驯妄,如果有一個(gè)校驗(yàn)失敗荷并,則校驗(yàn)狀態(tài)為1
isnormal_str+="if(check_status==0){if("+isnormalArray[i][0]+"_isnormal==0) check_status=1;}";
//check is normal? return not normal column
isnormal_str+="if("+isnormalArray[i][0]+"_isnormal==0){if(isnormal_column==\"\"){ isnormal_column = \""+ isnormalArray[i][0] +"\";}else{isnormal_column+=\"、\"+\""+isnormalArray[i][0]+"\";}}";
}
//最終輸出的錯(cuò)誤詳細(xì)情況
isnormal_str+="if(check_status==1){if(check_detail==\"\"){check_type=\"違反標(biāo)準(zhǔn)化規(guī)則\";check_detail=\"字段\"+ isnormal_column +\"違反了標(biāo)準(zhǔn)化規(guī)則\";}else{check_type+=\",\"+\"違反標(biāo)準(zhǔn)化規(guī)則\";check_detail+=\",字段\"+ isnormal_column +\"違反了標(biāo)準(zhǔn)化規(guī)則\";}}";
eval(isnormal_str);
//////////////////////////////數(shù)據(jù)類型校驗(yàn)//////////////////////////////////////////
var datatypeArray = [["ALTDATE","isDate"],["ALTAF","isNum"]];//二維數(shù)組青扔,第一列為要校驗(yàn)的數(shù)據(jù)字段源织,第二列為數(shù)據(jù)類型校驗(yàn)函數(shù)(isDate[日期]、isNum[數(shù)字]微猖、isMailValid[郵箱]谈息、isEmpty[空])
var datatype_str="";
var datatype_column="";
check_status=0;//校驗(yàn)狀態(tài)置0
for(var i=0;i<datatypeArray.length;i++){
//4:類型校驗(yàn)枚舉值
datatype_str+="var "+datatypeArray[i][0]+"_datatype=0;";
//數(shù)據(jù)類型校驗(yàn)枚舉值賦值
datatype_str+="var datatypesql_"+datatypeArray[i][0]+"=\"select "+datatypeArray[i][0]+" from "+ check_table +" where "+check_table_id+"='"+check_name+"'\";";
datatype_str+="if("+datatypeArray[i][1]+"(fireToDB(strConn,datatypesql_"+datatypeArray[i][0]+")[0][0])) "+ datatypeArray[i][0]+"_datatype=1;";
//校驗(yàn)所有需要校驗(yàn)的字段,如果有一個(gè)校驗(yàn)失敗励两,則校驗(yàn)狀態(tài)為1
datatype_str+="if(check_status==0){if("+datatypeArray[i][0]+"_datatype==0) check_status=1;}";
//check is datatype? return not datatype column
datatype_str+="if("+datatypeArray[i][0]+"_datatype==0){if(datatype_column==\"\"){ datatype_column =\""+datatypeArray[i][0]+"\";}else{datatype_column+=\"黎茎、"+datatypeArray[i][0]+"\";}}";
}
//最終輸出的錯(cuò)誤詳細(xì)情況
datatype_str+="if(check_status==1){if(check_detail==\"\"){check_type=\"違反數(shù)據(jù)類型規(guī)則\";check_detail=\"字段\"+datatype_column+\"違反數(shù)據(jù)類型規(guī)則\";}else{check_type+=\",\"+\"違反數(shù)據(jù)類型規(guī)則\";check_detail+=\",字段\"+datatype_column+\"違反數(shù)據(jù)類型規(guī)則\";}}";
eval(datatype_str);
//////////////////////////////////////////////////////////////////////////////////////
if(check_detail!="")
{
check_detail=check_detail+","+source_table_id+"="+check_name;
}
以下是執(zhí)行后的效果:
在此基礎(chǔ)上我們還可以擴(kuò)展更多的校驗(yàn),比如通過正則表達(dá)式的方式(利用kettle的isRegExp函數(shù))当悔,如下:
//////////////////////////////正則表達(dá)式校驗(yàn)//////////////////////////////////////////
var dataArray = [["Email","^\\w+@[a-zA-Z_]+?\\.[a-zA-Z]{2,3}$","^[\\w-\.]+@([\\w-]+\\.)+[\\w-]{2,4}$"]];//二維數(shù)組傅瞻,第一列為要校驗(yàn)的數(shù)據(jù)字段,第二列為規(guī)則1盲憎,第三列為規(guī)則2(可選)
var data_str="";
var data_column="";
check_status=0;//校驗(yàn)狀態(tài)置0
for(var i=0;i
//4:類型校驗(yàn)枚舉值
data_str+="var "+dataArray[i][0]+"_data=0;";
//數(shù)據(jù)類型校驗(yàn)枚舉值賦值
data_str+="var datasql_"+dataArray[i][0]+"=\"select "+dataArray[i][0]+" from "+check_table+" where "+ check_table_id +"='"+check_name+"'\";";
data_str+="if(isRegExp(fireToDB(strConn,datasql_"+dataArray[i][0]+")[0][0],dataArray[i][1],dataArray[i][2] )>-1) "+dataArray[i][0]+"_data=1;";
//校驗(yàn)所有需要校驗(yàn)的字段嗅骄,如果有一個(gè)校驗(yàn)失敗,則校驗(yàn)狀態(tài)為1
data_str+="if(check_status==0){if("+dataArray[i][0]+"_data==0) check_status=1;}";
//check is data? return not data column
data_str+="if("+dataArray[i][0]+"_data==0){if(data_column==\"\"){data_column=\""+ dataArray[i][0] + "\"; } else {data_column+=\"饼疙、"+dataArray[i][0]+"\";}}";
}
//最終輸出的錯(cuò)誤詳細(xì)情況
data_str+="if(check_status==1){if(check_detail==\"\"){check_type=\"違反數(shù)據(jù)類型規(guī)則\";check_detail=\"字段\"+ data_column +\"違反數(shù)據(jù)類型規(guī)則\";}else{check_type+=\",\"+\"違反數(shù)據(jù)類型規(guī)則\";check_detail+=\",字段\"+ data_column + \"違反數(shù)據(jù)類型規(guī)則\";}}";eval(data_str);
以上腳本的好處就是溺森,可以直接通過修改變量慕爬,就能對(duì)不同輸出表的不同字段進(jìn)行校驗(yàn),基本上不用修改邏輯代碼屏积,如果進(jìn)一步優(yōu)化一下医窿,就可以寫成函數(shù),直接調(diào)用炊林±崖可以把檢驗(yàn)字段和檢驗(yàn)規(guī)則進(jìn)一步參數(shù)化,通過調(diào)用參數(shù)表渣聚,來執(zhí)行數(shù)據(jù)驅(qū)動(dòng)的校驗(yàn)測(cè)試(這就是一種自動(dòng)化測(cè)試的思路)独榴。