在 Birt 中实现交叉表的动态分组
来源:
https://forums.opentext.com/forums/discussion/173783/dynamic-grouping-of-crosstab-in-birt#latest
在业务填报中,有时会需要基于时间段进行动态交叉分组统计,根据时间段长短实现按天、按周、按月、按年动态分组。例如:某企业根据业务需要,需按照2个参数(开始日期、结束日期)实现一段时间内订单的统计。统计规则如下:
示例:根据输入的参数值,计算日期之间的差异。
var diff = 结束日期-开始日期 ---- 相隔的天数
如果(diff <15)
将“日期组”分组以显示为日期
如果(diff>15)
将“日期组”分组以显示为周
如果(diff >30)
将“日期组”分组以显示为月份
如果(diff>365)
将“日期组”分组以显示为年份
小伙伴们是不是有点不知所措了呢?上述问题实质上就是一个数据准备的问题,可是SQL或scripted data sources的方式代码难写,工作量大;退而求次使用报表隐藏列的方式,既不通用又非常别扭。那么,一个更好的解决方案就是在报表工具中引入集算器,解决诸类问题将轻而易举。下面我们就以Birt报表工具为例,介绍一下实现过程。对于其他的报表工具,也是大同小异。
在本例中,要根据参数输入,统计企业从2012-07-04开始到2014-05-06结束这个时间段内的订单总数,运货费总数,订单金额总数。数据表“ORDERS”中的原始数据如下:
我们直接来看集算器解决这个问题的SPL代码:
A |
B |
C |
|
1 |
=connect("demo") |
//连接数据库 |
|
2 |
=A1.query("select ORDERID,ORDERDATE,FREIGHT,ORDERAMOUNT from ORDERS where ORDERDATE >=? and ORDERDATE <=?",startDate,endDate) |
//从 ORDERS 表中查询出统计开始日期到结束日期之间的订单数据,startDate 和 endDate 是日期参数。 |
|
3 |
=interval(startDate,endDate) |
//计算开始日期和结束日期的间隔天数 |
|
4 |
if A3>365 |
//如果天数间隔大于 365 天,则按年份分组 |
|
5 |
=startDate|A3.(elapse@y(startDate,~)) |
//计算出按年份的分组序表 |
|
6 |
=A2.group(B5.pseg(ORDERDATE);~.count(ORDERID):TotalOrder,round(~.sum(FREIGHT),2):TotalFreight,round(~.sum(ORDERAMOUNT),2):TotalOrderAmount,B5(#):BeginDate) |
//按 B5 区间对 A2 分组,统计出订单总数,运货费总数,订单金额总数,保留两位小数,并将 B5 作为最后一列。 |
|
7 |
=B6.new(BeginDate:BeginDate,#2:TotalOrder,#3:TotalFreight,#4:TotalOrderAmount) |
//取出需要的数据列,生成新的结果序表 |
|
8 |
>A1.close() |
//关闭数据库 |
|
9 |
return B7 |
//返回按年份分组的结果集 |
|
10 |
else if A3>30 |
//如果天数间隔大于 30 天 & 小于等于 365 天,则按月份分组 |
|
11 |
=startDate|A3.(elapse@m(startDate,~)) |
//计算出按月份的分组序表 |
|
12 |
=A2.group(B11.pseg(ORDERDATE);~.count(ORDERID):TotalOrder,round(~.sum(FREIGHT),2):TotalFreight,round(~.sum(ORDERAMOUNT),2):TotalOrderAmount,B11(#):BeginDate) |
//按 B11 区间对 A2 分组,统计出订单总数,运货费总数,订单金额总数,保留两位小数,并将 B11 作为最后一列。 |
|
13 |
=B12.new(BeginDate:BeginDate,#2:TotalOrder,#3:TotalFreight,#4:TotalOrderAmount) |
||
14 |
>A1.close() |
||
15 |
return B13 |
//返回按月份分组的结果集 |
|
16 |
else if A3>15 |
//如果天数间隔大于 15 天 & 小于等于 30 天,则按星期分组 |
|
17 |
=startDate|A3.(elapse(startDate,7*~)) |
//计算出按星期的分组序表 |
|
18 |
=A2.group(B17.pseg(ORDERDATE);~.count(ORDERID):TotalOrder,round(~.sum(FREIGHT),2):TotalFreight,round(~.sum(ORDERAMOUNT),2):TotalOrderAmount,B17(#):BeginDate) |
/按 B17 区间对 A2 分组,统计出订单总数,运货费总数,订单金额总数,保留两位小数,并将 B17 作为最后一列。 |
|
19 |
=B18.new(BeginDate:BeginDate,#2:TotalOrder,#3:TotalFreight,#4:TotalOrderAmount) |
||
20 |
>A1.close() |
||
21 |
return B19 |
//返回按星期分组的结果集 |
|
22 |
else |
//如果天数间隔小于 15 天,则按日期分组 |
|
23 |
=startDate|A3.(elapse(startDate,~)) |
//计算出按日期的分组序表 |
|
24 |
=A2.group(B23.pseg(ORDERDATE);~.count(ORDERID):TotalOrder,round(~.sum(FREIGHT),2):TotalFreight,round(~.sum(ORDERAMOUNT),2):TotalOrderAmount,B23(#):BeginDate) |
/按 B23 区间对 A2 分组,统计出订单总数,运货费总数,订单金额总数,保留两位小数,并将 B23 作为最后一列。 |
|
25 |
=B24.new(BeginDate:BeginDate,#2:TotalOrder,#3:TotalFreight,#4:TotalOrderAmount) |
||
26 |
>A1.close() |
||
27 |
return B25 |
//返回按日期分组的结果集 |
将集算器SPL代码存为order.dfx文件,然后引入到Birt报表中。如何引用请参看乾学院文章《BIRT调用SPL脚本》。
在BIRT报表中设计表如下:
报表调用集算器的方法和调用存储过程完全一样,比如在 BIRT 的存储过程数据集中可以用 call orders(?,?) 来调用。
接下来,我们看一下WEB预览时,输入不同参数的预览结果:
(1)输入参数:开始时间 2012-07-04,结束时间 2014-05-06 间隔天数大于365,按照年份分组显示。
(2)输入参数:开始时间 2012-07-15,结束时间 2012-12-03 间隔天数大于30,按照月份分组显示。
(3)输入参数:开始时间 2012-07-20,结束时间 2012-08-15 间隔天数大于15,按照星期分组显示。
(4)输入参数:开始时间 2012-07-04,结束时间 2012-07-18 间隔天数小于15,按照日期分组显示。