欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用集算器准备非常规格式报表的数据

程序员文章站 2022-05-31 21:27:00
...

  有些非常规的格式很难用报表工具提供的功能直接实现,但如果准备出合适的数据源,就能大大降低报表设计的难度。

  使用免费的集算器可以弥补这一不足。集算器提供了集合运算,支持动态脚本执行,还提供了简单易用的JDBC接口,报表工具可将集算器脚本文件当做数据库存储过程执行,传入参数并用JDBC获得返回结果。

  集算器与报表工具的集成结构如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

  下面举例说明集算器实现横向分栏的过程:

  报表工具大多有纵向分栏的功能,但很难实现记录横向摆放并分栏的布局。比如库表emp有3个字段,部分数据如下:

EId

Name

Dept

4

Emily

HR

5

Ashley

R&D

6

Matthew

Sales

7

Alexis

Sales

8

Megan

Marketing

9

Victoria

HR

10

Ryan

R&D

11

Jacob

Sales

  期望的报表布局是记录先横后纵摆放,且横向分为3栏,如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

  如果用集算器将原来的3字段数据转为9字段,就可以用报表工具实现横向分栏了,代码如下:

 

A

B

C

1

=myDB1.query(“select EId,Name,Dept from emp where EId>=? and EId<=? order by EId “,begin,end)

2

=A1.step(3,1) =A1.step(3,2)|[null] =A1.step(3,3)|[null]

3

=A2.derive(B2(#).EId:EId2,B2(#).Name:Name2,B2(#).Dept:Dept2,C2(#).EId:EId3,C2(#).Name:Name3,C2(#).Dept:Dept3)

4

result A3    

  A1:执行SQL,其中begin、end是报表参数。

  A2:每隔3条记录从A1取出第1条,组成新的二维表,B2、C2以此类推。由于B2、C2可能比A2少一条记录,因此需要在末尾追加一条空记录。运算符“|”表示将两个集合纵向合并。结果如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

  A3:将B2、C2横向拼接在A2上。B2(#).EId是第1个新列,表示取出B2中第#条记录的EId字段,符号“#”表示A2中每条记录的行号。A3就是报表需要的最终数据,如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

  报表工具可用JDBC的方式调用集算器脚本,就像调用普通数据库中的存储过程,形如:call 脚本文件名(参数1…参数N)。集算器的返回结果会以普通数据集的形式参与报表计算。具体用法可参考集算器集成与应用之JasperReport集成集算器集成与应用之BIRT集成

  作为专业的报表数据源工具,集算器还可以实现更多的计算,下面分别举例。

错行分栏

  将库表emp横向分为两栏,每行的第2栏和下一行的第1栏相同,报表布局如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

  集算器代码:

 

A

B

1

=myDB1.query(“select EId,Name,Dept from emp where EId>=? and EId<=? order by EId “,begin,end)  

2

=A1.conj([~[-1],~]).to(3,)  

3

=A2.step(2,1) =A2.step(2,2)|[null]

4

=A3.derive(B3(#).EId:EId2,B3(#).Name:Name2,B3(#).Dept:Dept2)  
       

  A2:错位拼接,将上一条记录和当前记录依次拼接起来,从第3行开始取拼接结果。结果如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

  A3、B3、A4:按照前面的例子横向分两栏。

  单字段纵向动态分栏

  按照先纵后横的布局将单字段结果集展现在报表中,行数和列数都是参数。源数据如下:

sOrder

 

26

33

84

133

32

39

43

71

99

20

83

97

107

135

142

1

 

  集算器代码:

 

A

1

=myDB1.query(“select orderID from sorder”).(orderID)

2

=Row.new(${Col.(“:c”+string(~)).string()})

3

=Col.(A2.field(~,to((~ -1)*Row+1,~*Row).(A1.m(~))))

4

result A2

  A1:取出单字段数据,转换为序列(有序集合)

  A2:生成与报表布局相同的二维表,初始值为空。参数Row和Col来自报表。

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

  A3:向A2追加数据,最终结果如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

简单行列转置

  数据库表SALES存储着订单数据,部分数据如下:

OrderID Client SellerId Amount OrderDate

1

DSG

13

19480

2014-06-20 00:00

2

ERN

18

979

2014-06-13 00:00

3

JFE

19

28972

2014-12-11 00:00

4

OFS

21

4829

2014-02-24 00:00

5

ERN

22

21392

2014-02-01 00:00

  现在要计算出2013年各月份订单的总金额、最大订单金额、最小订单金额,以及总订单数,并将数据转置成13列4行,即:四种算法是第一列,列名为subtotal,每个月占一列,列名分别是1、2、3、4…其中前五个字段如下:

subtotal

1

2

3

4

OSum

4176606

3645032

4361721

4670117

OMAX

27997

28021

27936

28022

OMIN

116

232

272

104

OCount

295

265

322

324

  集算器代码:

 

A

1

=db.query(“select  month(ORDERDATE) as MONTH,sum(AMOUNT) as OSum,max(AMOUNT) as OMAX, min(AMOUNT) as OMIN ,count(ORDERID) as OCount from sales where year(ORDERDATE)=2013 group by MONTH order by MONTH”)

2

=["OSum","OMAX","OMIN","OCount"].new(~:subtotal,${to(A1.len()).string()})

3

=A1.run(A2.field(#+1,OSum|OMAX|OMIN|OCount))

4

result A2

  A1:执行SQL,过滤出2013年的数据,并按月份分组汇总,结果如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

  A2:新建空序表,带默认值,用来存储最终结果。共13列,前几列如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

  A4:遍历A1,每次取1条记录,并从第2列开始填充A2。A2 最终如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

  A4:将A2返回给报表工具。

动态定位行列转置

  在库表tb中,userid相同的3条记录是一组数据,报表需要将组记录转为行记录。库表tb部分数据如下:

userid

type

descr

scooby

dog

dog

scooby

weight

50

scooby

hair

long

mickey

mouse

mouse

mickey

hair

 

mickey

weight

2

  理想的表样:

userid

type  

hair          

weight

mickey

mouse

 

2

scooby

dog

long

50

 

  集算器代码:

 

A

1

=$select * from tb

2

=A1.group(userid).new( userid,(t=~.align@n([‘hair’,’weight’],type).(descr))(3):type,t(1):hair,t(2):weight)

  A1:查询数据库;

  A2:分组,并将每组数据转为一条记录。函数group可对数据分组,函数new新建二维表,“~”表示分组后的每组数据。函数align可将数据按某集合成员([‘hair’,’weight’])对齐,@n表示将无法对齐的数据单列一行。结果如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

多层转置

  库表kpi中,f_site相同的4条记录是一组数据,部分数据如下

dataset_date

f_site

ioh_kpi

idh_kpi

iol_kpi

2015/04/21 13:15

X6SF_SARF1

1

2

3

2015/04/21 13:30

X6SF_SARF1

9

1

2

2015/04/21 13:45

X6SF_SARF1

8

9

1

2015/04/21 14:00

X6SF_SARF1

7

8

9

2015/04/21 13:15

XC_01

2

3

4

2015/04/21 13:30

XC_01

11

12

13

2015/04/21 13:45

XC_01

21

22

23

2015/04/21 14:00

XC_01

31

32

33

 

  现在要求对每组数据进行行列转置,按f_site分组,理想的表样如下:

site

KPI Name

2015/04/21 13:15

2015/04/21 13:30

2015/04/21 13:45

2015/04/21 14:00

X6SF_SARF1

ioh_kpi

1

9

8

7

idh_kpi

2

1

9

8

iol_kpi

3

2

1

9

XC_01

ioh_kpi

2

11

21

31

idh_kpi

3

12

22

32

iol_kpi

4

13

23

33

  集算器代码:

 

A

B

1

=myDB1.query(“select * from kpi order by f_site,dataset_date”)

2

=A1.id(dataset_date) =A1.fname().to(3,)

3

=create(site,’KPI Name’,${A2.string()})  

4

for A1.group(f_site) = A4.align(A2,dataset_date)

5

  >B2.run(A3.record([A4.f_site,~]|B4.field(~)))

6

result A3  

  A2:取得A1中不重复的dataset_date,即["2015-04-21 13:15","2015-04-21 13:30","2015-04-21 13:45","2015-04-21 14:00"] ;

  B2:取得A1中字段名,从第3个开始,即["ioh_kpi","idh_kpi","iol_kpi"];

  A3:新建空序表,用来存储最终结果。字段名分别为site,KPI Name,”2015-04-21 13:15″,”2015-04-21 13:30″,”2015-04-21 13:45″,”2015-04-21 14:00″ ;

  A4:按f_site分组,并循环每组数据。B4将A4按照A2对齐,数据不全则自动补位。B5用来向A3动态追加记录。

  A3是最终结果,A6会将A3返回报表工具,结果如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

复制行
  按次序将记录复制3份,并用报表展现。

  集算器代码:

 

A

1

=myDB1.query(“select * from sOrder”)

2

=A1.conj([~]*3)

 

  A2: []表示序列(有序集合),[~]表示将A1当前记录作为单成员序列,[~]*3可将当前记录复制3份,函数conj对A1每个记录执行计算,最后进行合并。计算结果如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

用条件控制分组表

  展现一张分组表,数据来自库表sOrder,分组字段是Seller,明细字段是Client和Amount。特殊要求是:
1.每组明细中,从第2条直到结束需要显示“+”号,第1条不显示。
2.如果每组明细多于1条,则在该组最后显示对Amount的汇总求和,明细只有1条时不显示汇总。表样示意如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

 

 

 

 

 

 

 

 

  集算器代码:

 

A

B

C

1

=myDB1.query(“select Seller,Client,Amount from sOrder where Amount>?”,arg)

2

=create(item,value)    

3

for A1.group(SellerId) >A2.insert(0:A3,if(#>1,”+”)+Client,Amount)

4

  if A3.len()>1 >A2.insert(0,A3.SellerId+”subtotal:”,A3.sum(Amount))

5

result A2    

  A1:SQL查询。

  A2:创建空二维表,存放最终结果。

  A3:按Seller分组,并循环每组数据。循环作用范围即缩进的B3-C4,循环中可用A3引用循环变量

  B3:向A2追加当前组明细,如果序号#大于1,则在Client之前加“+”。

  B4-C5:如果当前组记录数大于1,则向A2追加subtotal。A2最终结果如下:

用集算器准备非常规格式报表的数据
            
    
    博客分类: Java相关 报表数据源转置横向分栏动态定位集算器

  A5:将A2通过jdbc传回报表工具。