利用kettle的JS进行ETL数据校验(升级版)

无意中在网上看到一篇文章《利用kettle中的JS来完成ETL数据校验》,挺受启发的,觉得用JS来实现ETL的自动化校验,是个不错的思路。但是这篇文章里给的JS脚本样例确实有待改进,一是让初学者看着不那么清晰,二是扩展性和维护性都较差。于是我做了二次改造,重新编写了脚本,如下:

//Script here

var strConn = "TestOrcl";

var check_status=0;//如果检测到有任何一种校验错误,则check_status=1

var check_table="E_OT_PRMTALT";//校验有关的表名字

var check_table_id="LICALTID";//校验表主键

var check_name=LICALTID;//校验表主键值

var check_detail="";//校验到的错误详细情况

var check_type="";//校验到的错误类型

var check_date=new Date();//校验时间

var source_table="E_OT_PRMTALT";//数据源表名称,如果数据来自多个数据表,则需要声明多个

var source_table_id="LICALTID";//数据源表主键,如果多个表联合主键,则需要声明多个主键

/////////////////////////////字段唯一性校验//////////////////////////////////////////

var isuniqueArray=new Array("LICALTID","LICID");//一维数组,表的字段名

var isunique_str="";

var isunique_column="";

for(var i=0;i<isuniqueArray.length;i++){

//1:唯一性枚举值

  isunique_str+="var "+isuniqueArray[i]+"_isunique=0;";

  //唯一性校验枚举值赋值

  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;}";

  //校验所有表需要校验的字段,如果有一个校验失败,则校验状态为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]+"\";}}"; 

}

//最终输出的错误详细情况

isunique_str+="if(check_status==1){check_type=\"违反唯一规则\";check_detail=\"表\"+source_table+\"中,字段\"+isunique_column+\"违反了唯一规则\";}";

eval(isunique_str);

//////////////////////////////////////////////////////////////////////////////////

/////////////////////////////字段非空校验//////////////////////////////////////////

var isnullArray=new Array("ALT","ALTBE","ALTAF","ALTDATE");//一维数组,表的字段名

var isnull_str="";

var isnull_column="";

check_status=0;//校验状态置0

for(var i=0;i<isnullArray.length;i++){

//2:非空枚举值

isnull_str+="var "+isnullArray[i]+"_isnull=0;";

//非空校验枚举值赋值

isnull_str+="if("+isnullArray[i]+"==null||"+isnullArray[i]+"==\"\"){"+isnullArray[i]+"_isnull=1;}";

//校验所有表需要校验的字段,如果有一个校验失败,则校验状态为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]+"\";}}";

}

//最终输出的错误详细情况

isnull_str+="if(check_status==1){if(check_detail==\"\"){check_type=\"违反非空规则\";check_detail=\"字段\"+ isnull_column +\"违反了非空规则\";}else{check_type+=\",\"+\"违反非空规则\";check_detail+=\",字段\"+ isnull_column +\"违反了非空规则\";}}";

eval(isnull_str);

//////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////标准值校验//////////////////////////////////////////

var isnormalArray = [["S_EXT_FROMNODE","in ('220000')"],["ALT","in ('许可文件编号','许可文件名称','许可机关','许可内容')"]];//二维数组,第一列为字段,第二列为匹配规则

var isnormal_str="";

var isnormal_column="";

check_status=0;//校验状态置0

for(var i=0;i<isnormalArray.length;i++){

//3:标准化枚举值

isnormal_str+="var "+isnormalArray[i][0]+"_isnormal=0;";

//标准化校验枚举值赋值

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;}";

//校验所有表需要校验的字段,如果有一个校验失败,则校验状态为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]+"\";}}";

}

//最终输出的错误详细情况

isnormal_str+="if(check_status==1){if(check_detail==\"\"){check_type=\"违反标准化规则\";check_detail=\"字段\"+ isnormal_column +\"违反了标准化规则\";}else{check_type+=\",\"+\"违反标准化规则\";check_detail+=\",字段\"+ isnormal_column +\"违反了标准化规则\";}}";

eval(isnormal_str);

//////////////////////////////数据类型校验//////////////////////////////////////////

var datatypeArray = [["ALTDATE","isDate"],["ALTAF","isNum"]];//二维数组,第一列为要校验的数据字段,第二列为数据类型校验函数(isDate[日期]、isNum[数字]、isMailValid[邮箱]、isEmpty[空])

var datatype_str="";

var datatype_column="";

check_status=0;//校验状态置0

for(var i=0;i<datatypeArray.length;i++){

//4:类型校验枚举值

datatype_str+="var "+datatypeArray[i][0]+"_datatype=0;";

//数据类型校验枚举值赋值

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;";

//校验所有需要校验的字段,如果有一个校验失败,则校验状态为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]+"\";}}";

}

//最终输出的错误详细情况

datatype_str+="if(check_status==1){if(check_detail==\"\"){check_type=\"违反数据类型规则\";check_detail=\"字段\"+datatype_column+\"违反数据类型规则\";}else{check_type+=\",\"+\"违反数据类型规则\";check_detail+=\",字段\"+datatype_column+\"违反数据类型规则\";}}";

eval(datatype_str);

//////////////////////////////////////////////////////////////////////////////////////

if(check_detail!="")

{

check_detail=check_detail+","+source_table_id+"="+check_name;

}

以下是执行后的效果:

在此基础上我们还可以扩展更多的校验,比如通过正则表达式的方式(利用kettle的isRegExp函数),如下:

//////////////////////////////正则表达式校验//////////////////////////////////////////

var dataArray = [["Email","^\\w+@[a-zA-Z_]+?\\.[a-zA-Z]{2,3}$","^[\\w-\.]+@([\\w-]+\\.)+[\\w-]{2,4}$"]];//二维数组,第一列为要校验的数据字段,第二列为规则1,第三列为规则2(可选)

var data_str="";

var data_column="";

check_status=0;//校验状态置0

for(var i=0;i

//4:类型校验枚举值

data_str+="var "+dataArray[i][0]+"_data=0;";

//数据类型校验枚举值赋值

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;";

//校验所有需要校验的字段,如果有一个校验失败,则校验状态为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]+"\";}}";

}

//最终输出的错误详细情况

data_str+="if(check_status==1){if(check_detail==\"\"){check_type=\"违反数据类型规则\";check_detail=\"字段\"+ data_column +\"违反数据类型规则\";}else{check_type+=\",\"+\"违反数据类型规则\";check_detail+=\",字段\"+ data_column + \"违反数据类型规则\";}}";eval(data_str);

以上脚本的好处就是,可以直接通过修改变量,就能对不同输出表的不同字段进行校验,基本上不用修改逻辑代码,如果进一步优化一下,就可以写成函数,直接调用。可以把检验字段和检验规则进一步参数化,通过调用参数表,来执行数据驱动的校验测试(这就是一种自动化测试的思路)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容