解决 Jasper 等报表工具制作报表中的几个难题
在制作业务报表时,经常会遇到一些单独依靠报表工具难以解决的问题。本文将针对几个 Jasper 报表工具用户在国外论坛中提出的现实问题,介绍如何用集算器 SPL 语言加以解决的方案。这里的解决方案其实并不仅适用于 Jasper,对其它报表工具也同样适用。
1. 计算账户各期余额
数据文件 data.csv 存储着某账户各期资金存取情况,在已知账户初始余额为 43 的情况下,需要根据该文件计算出各期余额,部分源数据如下:
Inputs,Outputs 0,10 15,0 22,0 0,33 0,15 0,14 36,0 0,69 2,0 18,0 |
想要得到的报表结果如下:
根据存取金额计算各期余额时需要进行跨行计算,可以用 Jasper 表达式实现,但实现步骤复杂且有一定难度,而通过集算器协助 Jasper 则可以轻松实现。具体的集算器 SPL 代码如下:
A |
|
1 |
=file("data.csv").import@tc() |
2 |
return (t=43,A1.derive(t=t+Inputs-Outputs:Balance)) |
A1 读入文件,选项 @tc 表示文件有标题行、以逗号为分隔符。
A2 计算各期余额并将计算结果返回给报表。其中,设置账户初值 t 为 43,然后在 A1 序表中增加一个计算列,其值为上期余额 + 本期流入 - 本期流出。显然这里的计算结果就是希望报表呈现的内容。
将以上 SPL 代码存为文件 balance.dfx。
为了在报表中呈现计算结果,可以利用集算器对外提供 JDBC 接口。在报表工具中通过建立 JDBC 数据源引入集算器脚本,而报表调用集算器定义的方法和调用存储过程一样,在 Jasper 的 SQL 设计器中可以用 call balance() 来调用并传入参数。详细步骤请参看《JasperReport 调用 SPL 脚本》。
然后,在 Jasper 中设计最简单的 list 表,模板如下:
预览后可以看到报表结果,和我们要求的一样:
2. 计算贷款分期
数据库表 loan 存储着贷款信息,包括贷款总额、按月分期数、年利率。要求实现一张分组表,在每条贷款信息下列出各期明细,包括:当期还款额、当期利息、当期本金、剩余本金。
表 loan 的部分数据如下:
LoanID |
LoanAmt |
Term |
Rate |
L01 |
100000 |
5 |
4.75 |
L02 |
20000 |
2 |
5 |
L03 |
500000 |
12 |
4.5 |
想要得到的报表结果如下图:
根据贷款额计算贷款分期时需要进行循环计算和跨行计算,用存储过程或 Scriptlets 实现的难度较大,而同样使用集算器协助 Jasper 就可以轻松实现。编写集算器 SPL 代码如下:
A |
|
1 |
=db.query("select * from loan") |
2 |
=A1.derive(Rate/100/12:mRate,LoanAmt*mRate*power((1+mRate),Term)/(power((1+mRate),Term)-1):mPayment) |
3 |
=A2.((t=LoanAmt,Term.new(A2.LoanID:LoanID, A2.LoanAmt:LoanAmt, A2.mPayment:payment, A2.Term:Term,A2.Rate:Rate, t*A2.mRate:interest, payment-interest:principal, t=t-principal:principlebalance))) |
4 |
=A3.conj() |
5 |
return A4 |
A1 执行 SQL,取出 loan 中的记录。
A2 在序表 A1 中新增计算列月利率 mRate 和每期还款额 mPayment。结果如下:
A3 根据贷款信息计算各期明细。A2.()是循环函数,可对 A2 的成员依次进行计算,“()”内的代码将分步计算,最终返回最后一个逗号的计算结果。其中函数 new 用来生成新的二维表。A3 的计算结果是层次数据,如下:
A4 合并层次数据,形成分期明细二维表。
A5 返回结果给报表。
同样,在 Jasper 中可以设计一张简单的分组表,模板如下:
预览后就可以看到需要的的报表结果了。
3. 计算交叉表增长率
数据库表 store 存储着多种产品在 2014、2015 年的销售量,需要用交叉表呈现每种产品每年的销售量,并计算出各产品的年增长率。部分源数据如下:
Year item quantity 2014 Book 35 2015 Pencil 50 2014 Pencil 56 2015 Book 67 |
想要得到如下报表结果:
因为交叉表的每一列都是动态生成的,进行列间计算时又需要动态引用,因此用 Jasper 脚本实现这种需求有一定难度,而用集算器在数据准备阶段实现相应的计算就相对简单很多。集算器 SPL 代码如下:
A |
|
1 |
=mydb.query("select * from store order by item,year") |
2 |
=A1.group(item).run(A1.record(["Growth Rate",item,~(2).quantity/~(1).quantity-1])) |
3 |
return A1 |
A1 取出 store 表的记录。
A2 追加各产品的年增长率。其中,group 按产品分组,run 对每组数据依次计算,record 追加记录,~(i)表示当前组中的第 i 条记录。
A3 将计算结果返回给报表。
在 Jasper 中设计最简单的交叉表,模板如下:
预览后可以看到报表结果: