BIRT自带的Data Sources Join以及用ETL转化为同库等方案都难以解决此类问题。具体可以通过如下示例讨论:
交易明细数据(trade表)存储于生产系统的数据库DB2中,另外一部分业务数据(network表、account表)存储于业务系统的Mysql中,它们其中的关联关系如下图所示:
所谓“动态关联”,是指用户在前台界面输入参数,报表通过参数来决定trade和哪张表做关联,并在报表中显示关联后的数据,实际运算中可能还要进行数据过滤和汇总。查询流程如下图所示:
比如查询场景一:报表根据传入参数,能动态地将trade中的outAccount字段和account中的accountNo字段关联,最后查询结果显示trade中的所有字段以及account的name,gender,city等字段。
解决此类问题的常见方案与不足,分析如下:
1、BIRT Data Sources Join的问题在于要求表名和字段名是已知、确定的,但这类报表都是通过参数来动态关联的,因此无法实现。
2、可以用ETL把生产库的数据抽取到业务库,这样跨库的问题就转化为同库了。这个方案思路简单但实施起来细节上有很多难点。首先是实时查询:为了实时查询数据,需要在生产库使用触发器之类的功能来检测数据的实时变化,并将数据推送到业务库,但生产库不能轻易改动,因此实时查询就无法实现。非实时查询也难以办到,这是因为生产库的数据极其庞大,不可能每次都全部取过来,只有用增量抽取的办法,而判断增量就需要在trade表中加入时间戳字段。同样,生产库是不允许有这种改动的,因此也无法实现。
3、从能力上讲,BIRT JAVA bean data source是真正能解决报表问题,它比Data Sources Join更具灵活性,也不需要修改生产库。但这个方案只有一个缺陷:代码过于复杂,原因在于数据计算并非JAVA特长,若每次遇到跨库问题都用硬编码方式来实现,并不现实。
建议使用集算器,它是独立的数据计算引擎,拥有不依赖于数据库的计算能力,支持异构数据源的混合运算,比较适合进行动态关联再计算,事实上,可以把集算器看作是语法更简单的BIRT JAVA bean data source。比如实现上面的问题,集算器脚本只需6行:
| A |
1 | =DB2.query("select runningNo,networkNo,outAccount,amount from trade") |
2 | ="select"+crossJoinField+","+crossOtherFields+"from"+crossTable |
3 | =Mysql.query(A2) |
4 | =join(A1:trade,${tradeJoinField};A3:cross,${crossJoinField}) |
5 | =crossOtherFields.array().("cross."+~).string() |
6 | =A4.new(trade.runningNo,trade.networkNo,trade.outAccount,trade.amount,${A5}) |
其中 tradeJoinField,crossJoinField,crossOtherFields,crossTable 为输入参数。最后将计算结果返回给BIRT的DataSet进行报表展现。从此示例来看,集算器的参数用法很灵活,非常适合这类动态关联查询。由于它是专门的计算语言,所以较于常规办法,跨库计算的代码更加精炼易懂。
其实还有很多类似的跨库、分库计算问题,若有集算器SPL的辅助会很简单,感兴趣可以参考:分库后的统计查询
集算器提供了JDBC驱动,可以很方便的与BIRT等报表工具集成,BIRT调用SPL脚本有使用和获得它的方法。
关于集算器安装使用、获得免费授权和相关技术资料,可以参见如何使用集算器。