一个crystal report水晶报表无法实现的多数据源计算
2014-01-23 09:14
267 查看
最近帮用户解决了一个crystalreport多数据源计算的问题。由于计算过程有一定的复杂性,依靠报表工具自身的功能很难实现。
项目背景:用户新上线了绩效考核系统,原本的工资算法需要相的调整。以前的工资表主要由员工的基本工资计算得到,基本工资存储在财务管理软件的MSSQL数据库中。新的工资表由基本工资+绩效工资组成。绩效工资由绩效分数计算得出,而绩效分数存储在绩效考核系统的Oracle数据库中。显然,新的工资表需要两个数据库的跨库计算才能得到。
具体的绩效工资算法比较复杂。首先,不同的岗位算法不同。有些岗位是根据基本工资的区间来计算的,而有些岗位不需要按区间来计算。有些岗位只是单纯的用绩效来计算,而有些岗位要考虑绩效和工龄双重因素。还有些岗位有绩效得分但没有绩效工资。其次,同样是按基本工资区间来计算绩效的岗位,不同的岗位其区间划分方法、每个区间内的具体算法也有不同。最后,所有的员工工资要合并为一张报表。
为了便于理解,这里将算法大幅简化,并去掉交税的影响,岗位也简化为2个:normal和sales。Normal有绩效得分但没有绩效工资,其税前工资=基本工资。sales的税前工资=基本工资+绩效工资。其中绩效工资是这样算的:
(1)基本工资在2000以下的:基本工资*(绩效得分/100);
(2)基本工资在2000至4000的:基本工资*((绩效得分*0.9)/100);
(3)基本工资在4000以上的基本工资*((绩效得分*0.8)/100);
可以看到,要计算完整的工资表,需要将MSSQL的employee表按照岗位分成多份(简化后是2份),每份数据单独计算出税前工资,最后再将不同岗位的税前工资合并起来。两种岗位的算法不同,岗位是sales的需要关联Oracle中的performance表,其税前工资需要按不同的区间分别计算。而岗位是normal不需要做这种关联计算。
这张报表的难点在于:一、employee和performance分属不同的数据库,需要跨库计算。二、算法较复杂,仅将两张表简单地关联起来是无法实现目标的。
跨库计算最理想的解决方案是依靠报表工具。如果报表工具能在一张报表中处理两种数据源就可以实现“报表层跨库”。但Crystal report处理多数据源的办法很复杂,实现成本不低。而且报表工具也只能提供简单的内外关联,难以处理这种循环中判断以及多结果集合并的复杂算法。
报表工具无法解决这种问题,只能从报表之外寻求解法。事先ETL到一个库里显然不是个好办法,一方面ETL开发成本太高,另一方面还有数据同步和实时性的麻烦。自定义数据源可以解决这个问题,而集算器可以很好地为报表工具提供自定义数据源。
上述代码很容易解读。
A1、A2:分别从ORACLE和MSSQL取数据。
A3:为employee加一个空列preTax,用来存储将来的税前工资。
A4、A10:从employee分别取出岗位是sales和normal的数据。由于后期要合并,用业务名引用比较方便,因此这两部分数据分别定义为sales和normal。当然,A3这种临时的计算结果并没有额外定义变量,而是直接在A4中按格名来引用A3。类似的还有A5中引用A1。
A5-C9:计算sales的税前工资。其中A5是关联计算,将sales的基本工资和绩效分数关联了起来。A6到C9是个循环,将sales逐条循环判断,按不同区间不同算法来计算税前工资。这里需要注意三点。一是循环体是用缩进来表示的,B7-C9都是循环体。二是循环变量就是for所在的单元格,即A6。循环体中可以用A6来表示当前记录。三是A6.empID.score的用法,这是对象的引用方式。这表示当前记录A6的empID字段所关联的记录(即performance中的记录)的score字段,即当前员工的绩效分数。
A11:直接将normal的preTax赋值为baseSalary。
A12:将不同岗位的计算结果合并起来。当然,实际的算法中远不止两种岗位,每种岗位的税前工资算法也比示例中复杂。
A13:从A12中挑选一些需要输出的字段。
A14:以JDBC的形式输出A13,以便JAVA代码或报表工具通过JDBCURL直接调用。可以看到,这实际上这也是一种将多数据源合并为单数据源的方法,只是Crystal的数据源关联过于简单,无法实现这种过程性的跨库计算罢了。
可以看到,Crystal report中的这个跨库的问题被轻松解决了。另外Crystal report会把集算器当作MSSQL或Oracle这样的数据库来调用,配合起来也很容易。
项目背景:用户新上线了绩效考核系统,原本的工资算法需要相的调整。以前的工资表主要由员工的基本工资计算得到,基本工资存储在财务管理软件的MSSQL数据库中。新的工资表由基本工资+绩效工资组成。绩效工资由绩效分数计算得出,而绩效分数存储在绩效考核系统的Oracle数据库中。显然,新的工资表需要两个数据库的跨库计算才能得到。
具体的绩效工资算法比较复杂。首先,不同的岗位算法不同。有些岗位是根据基本工资的区间来计算的,而有些岗位不需要按区间来计算。有些岗位只是单纯的用绩效来计算,而有些岗位要考虑绩效和工龄双重因素。还有些岗位有绩效得分但没有绩效工资。其次,同样是按基本工资区间来计算绩效的岗位,不同的岗位其区间划分方法、每个区间内的具体算法也有不同。最后,所有的员工工资要合并为一张报表。
为了便于理解,这里将算法大幅简化,并去掉交税的影响,岗位也简化为2个:normal和sales。Normal有绩效得分但没有绩效工资,其税前工资=基本工资。sales的税前工资=基本工资+绩效工资。其中绩效工资是这样算的:
(1)基本工资在2000以下的:基本工资*(绩效得分/100);
(2)基本工资在2000至4000的:基本工资*((绩效得分*0.9)/100);
(3)基本工资在4000以上的基本工资*((绩效得分*0.8)/100);
可以看到,要计算完整的工资表,需要将MSSQL的employee表按照岗位分成多份(简化后是2份),每份数据单独计算出税前工资,最后再将不同岗位的税前工资合并起来。两种岗位的算法不同,岗位是sales的需要关联Oracle中的performance表,其税前工资需要按不同的区间分别计算。而岗位是normal不需要做这种关联计算。
这张报表的难点在于:一、employee和performance分属不同的数据库,需要跨库计算。二、算法较复杂,仅将两张表简单地关联起来是无法实现目标的。
跨库计算最理想的解决方案是依靠报表工具。如果报表工具能在一张报表中处理两种数据源就可以实现“报表层跨库”。但Crystal report处理多数据源的办法很复杂,实现成本不低。而且报表工具也只能提供简单的内外关联,难以处理这种循环中判断以及多结果集合并的复杂算法。
报表工具无法解决这种问题,只能从报表之外寻求解法。事先ETL到一个库里显然不是个好办法,一方面ETL开发成本太高,另一方面还有数据同步和实时性的麻烦。自定义数据源可以解决这个问题,而集算器可以很好地为报表工具提供自定义数据源。
上述代码很容易解读。
A1、A2:分别从ORACLE和MSSQL取数据。
A3:为employee加一个空列preTax,用来存储将来的税前工资。
A4、A10:从employee分别取出岗位是sales和normal的数据。由于后期要合并,用业务名引用比较方便,因此这两部分数据分别定义为sales和normal。当然,A3这种临时的计算结果并没有额外定义变量,而是直接在A4中按格名来引用A3。类似的还有A5中引用A1。
A5-C9:计算sales的税前工资。其中A5是关联计算,将sales的基本工资和绩效分数关联了起来。A6到C9是个循环,将sales逐条循环判断,按不同区间不同算法来计算税前工资。这里需要注意三点。一是循环体是用缩进来表示的,B7-C9都是循环体。二是循环变量就是for所在的单元格,即A6。循环体中可以用A6来表示当前记录。三是A6.empID.score的用法,这是对象的引用方式。这表示当前记录A6的empID字段所关联的记录(即performance中的记录)的score字段,即当前员工的绩效分数。
A11:直接将normal的preTax赋值为baseSalary。
A12:将不同岗位的计算结果合并起来。当然,实际的算法中远不止两种岗位,每种岗位的税前工资算法也比示例中复杂。
A13:从A12中挑选一些需要输出的字段。
A14:以JDBC的形式输出A13,以便JAVA代码或报表工具通过JDBCURL直接调用。可以看到,这实际上这也是一种将多数据源合并为单数据源的方法,只是Crystal的数据源关联过于简单,无法实现这种过程性的跨库计算罢了。
可以看到,Crystal report中的这个跨库的问题被轻松解决了。另外Crystal report会把集算器当作MSSQL或Oracle这样的数据库来调用,配合起来也很容易。
相关文章推荐
- 一个crystal report水晶报表无法实现的多数据源计算
- 无法计算未实现 ICollection 的数据源中的计数
- 网页中实现一个计算当年还剩多少时间的倒数计时程序,要求网页上实时动态显示"××年还剩××天××时××分××秒"
- 润乾集算报表实现动态数据源
- C#实现计算一个点围绕另一个点旋转指定弧度后坐标值的方法
- 使用Olami SDK实现一个语音输入数字进行24点计算的iOS程序
- JavaScript实现-计算一个整数的阶乘-Factorialize a Number
- git是一种分布式代码管理工具,git通过树的形式记录文件的更改历史,比如: base'<--base<--A<--A' ^ | --- B<--B' 小米工程师常常需要寻找两个分支最近的分割点,即base.假设git 树是多叉树,请实现一个算法,计算git树上任意两点的最近分割点。 (假设git树节点数为n,用邻接矩阵的形式表示git树:字符串数组matrix包含n个字符串,每个字符串由字符'0
- 编写一个程序,定义一个职工类,输入3个职工的编号、姓名、工资和年龄, 类中的成员函数实现输入、输出,在主函数中定义对象,并计算输出3个职工的平均工资。
- JavaScript 网页中实现一个计算当年还剩多少时间的倒数计时程序
- 写4个同名方法,实现两个整数、两个实数,一个实数一个整数,一个整数一个实数之间的求和。在主调函数中调用这4个方法计算相关的值。(方法的重载)
- 一个不认真引发的数据无法录入润乾报表中的问题
- ActiveReports 报表控件V12新特性 -- 无需ETL处理,即可实现跨数据源分析数据
- 编写一个程序,实现设置上月、本月电表读数,显示上月、本月电表读数,计算并显示本月用电数。 *假设每度电的价格为1.2元,计算并显示本月电费
- 一个通用的加法计算,适合所有类型 注:不用方法重载实现
- javascript实现获取一个日期段内每天不同的价格(计算入住总价格)
- 用集算器实现跨行组计算报表
- django 模板中无法实现计算,收集的方案。在django template 中实现乘法,除法运算
- ireport_几种不同的数据源_实现报表制作
- 本题要求实现一个函数,计算阶数为n,系数为a[0] ... a[n]的多项式f(x)=∑ i=0 n (a[i]×x i ) 在x点的值。