在一些生产性行业中,不同指标数据在数据库中存储是按照列方式存储,也就是每个指标一个列字段,但是在报表展现或者页面输入数据时需要将这些列转为行的方式,下面通过一个实例看下如何实现填报表的行列转换 在报表中录入数据时如何实现行列转换
应用场景及需求:
某电力集团在实际应用中需要在填报数据时将数据库中的字段以更符合业务人员使用习惯的方式进行呈现,其中就有行列转换的情况。在常规的应用开发中,一般都是通过专门设计的数据界面进行录入,然后再通过程序转换存入数据库。而现在有了集算器支持的润乾填报表,就能够处理各种有关数据结构的填报需求了,这种行列转换自然也不在话下。
首先,我们来看一下行列转换的准确含义:
在一些企业应用中,一些指标项在数据库存储时会做为不同的字段存储,这样数据结构会更加清晰,但是在报表展示或填报表数据录入时,又需要将列转换成行的形式,从而更加符合业务人员的使用习惯,这就是行列转换。首先看一个报表展示页面:
需求一:这个填报表是月度报表,要求按照月份查询某公司下各项目以及机组信息数据,并且能够对数据进行修改。
需求二:工具栏中增加两个按钮:“报表保存”保存当前页面数据,“报表锁定”能够对当前页面数据进行保存并对数据锁定,锁定后用户再次访问该月份数据就无法再修改了。
需求三:报表第二列是项目名称。用户系统结构比较特殊,页面中每个项目名称都是数据库表中的字段名称,第三列和第四列为机组信息数据,在数据库中每个机组为一条记录,也就是说数据存放在数据库中两个表中,分别是 rep_tl_config 表和 rep_tl_yb 表,取数或回写时要根据项目名称从不同表中取数或回写。
下面是这些需求的实现过程。
解决方案:
这个报表的格式相对比较简单,按照需求制作即可,如下图:
A 列为序号列,单元格中设置序号。
B 列为项目名称
C 设置,B 列中项目名称中是有特殊符号的,和数据库中字段名称无法完全对应,会对取数造成影响,所以增加了 C 列,单元格类型为维度格,值为对应的字段名称。
D 列、E 列为数值格,该报表要取两个机组的数据,分别显示在 D 列、E 列中。
F 列为固定列,输入相应信息即可,
G 列用于控制页面端加锁后数据是否能够被修改。
C、D、E、G 列均需要设置字段名称,根据数据取数的数据对象来确定。
取数设置
由于数据结构较为特殊,所以取数使用集算器文件(dfx),并且由于报表中数据来自数据库两张数据表,所以取数脚本分两部分处理,脚本一如下:
A1:链接数据源
D1:单元格从数据表中取出公司名称赋值给变量:公司名称
E1:填报表首次访问时,如果没有传入年月,则取当前系统时间上月数据,表达式为:>month=if(month==null,pdate@m(now()),date(month/“-01”))
A2、A3 单元格分别定义了从两个数据表中取数的字段名称
D4、E4 分别定义两个变量设置机组名称,groupID 为机组传入参数,传入格式为 #1#2 方式,所以此处做了拆分。
A5:从 rep_tl_config 表中取出需要数据,数据返回如下:
A6:使用集算器的 pivot 函数,将 A5 中的数据做行列转换,将列转成行,将字段名称转为行数据。
A8:将 A7 数据按照脱硫设备编号进行分组拆分,将数据放到 data 列中
A9、B9、C9 取第一个脱硫编号的数据,处理后放到 t1 对象中
A10、B10、C10 取第二个脱硫编号的数据,处理后放到 t2 对象中
A11:通过序号字段,将 t1、t2 两个对象关联在一起
A12:取出需要数据,此时数据格式为:
可以看到,已经将数据进行了行列转换,原来的字段做为项目字段中的值,另外两列存储对应的数据值。
A13:将 A12 单元格数据赋值给 tl_config 对象
至此,第一部分取数完成,接下来看下第二部分数据处理。
A16:从 rep_tl_yb 表中取出相应数据
B16:设置页面端是否加锁标志,数据表中有个字段“是否经过修正”,判断 A16 是否为空,如果为空,那么证明是第一次访问该月数据,所以值为 false,否则取数据库中对应值。
A17 中做判断,如果 A16 数据为空,则直接在之前定义的 tl_config 对象基础上增加公司名称、month、是否经过修正、flag 字段,返回给报表,即报表第二部分数据为空。
B22~B30 之间单元格设置和脚本一中设置设置方式类似,由于篇幅原因,此处不做过详细说明,最终将所需要数据放到 tl_config 对象中,tl_config 对象中数据为:
接下来,设置填报表中对应单元格的字段名称,将 C 列单元格字段名称设置为:tl_config. 项目,D 列字段名称设置为:1 脱硫装置,E 列字段名称设置为:2 脱硫装置,G 列设置为:是否经过修正
这样,填报表能够从数据库中取出相应数据展示到页面中。
数据回写
接下来看下数据回写脚本,同样,回写时也需要将数据回写到数据库的两个表中,此处脚本分两段来说明:
B1:取出公司名称
D1:设置 month 对象值,如果传入参数为空,则取当前系统时间的前一个月
A2、A3 分别定义两个表中的字段名
D4、E4,分别解析两个机组编号放大 groupID1、groupID2 中
A7:>tl_config=tl_config.new(项目,1 脱硫装置,2 脱硫装置, 是否经过修正),从 tl_config 对象中取出相应字段,并生成新对象 tl_config
A9:从对象中取出项目在 A2 中的数据,A2 为数据库表 rep_tl_config 中字段名
B9:=A9.new(#1,#2).derive(groupID1: 脱硫设备编号,kks:kks 编码,B1(1). 所属公司: 所属公司 ),从 A9 中取第 1、第 2 两列数据,并且增加相应字段,之前看过 tl_config 对象中数据,1、2 列中存储的是项目名称、机组 1 数据
C9:=B9.pivot(kks 编码, 脱硫设备编号, 所属公司;#1,#2),通过 pivot 函数,将行在转回成列形式。
B10、C10,取 1、3 列,同上,将机组 2 数据取出并作行列转换。
A11:>A1.update@u(C9|C10,rep_tl_config,${C9.fname().concat(“,”)};kks 编码, 脱硫设备编号, 所属公司 ),用 update 函数执行更新操作,将页面中数据更新到 rep_tl_config 表中,其中 C9|C10 是将机组 1 和机组 2 纵向拼接,fname() 取 C9 的字段名,并转换成字符串格式。
这样,rep_tl_config 表更新完毕,接下来看下 rep_tl_yb 表的处理,脚本如下:
处理方式和之前一样,A3 单元格定义的是 rep_tl_yb 中的字段名称,在 A14~A17 中按照之前方式,取出对应字段并通过 pivot 做行列转换,将数据更新到数据库即可。
这样就完成了数据的取数及回写操作。
加锁设置
在取数对象中,取出了数据库的是否经过修正字段,通过该字段的值控制页面中的数据是否经过锁定,该字段的值在报表的 G 列中取出,所以报表可以根据 G 列的值控制页面端是否能够修改数据,是否修改数据可以通过报表单元格的是否可编辑表达式属性控制,在 D、E 两列(两个机组数据列)的是否可编辑表达式中写入:G4!=“true”,表示 G4 单元格不为 true 时,在页面端可编辑。
上述完成了报表取数时可以根据相应字段控制页面端是否能够修改数据,接下来看下,如果在页面端点击报表锁定按钮,实现数据加锁操作。
报表工具栏默认使用的是 inputtoolbar.jsp,里边定义了工具栏的按钮,可在该页面自定义按钮:
里边增加按钮,点击时调用 submit 函数,在 showInput.jsp 中增加 submit 函数如下:
function submit(arg1){
for(var i=4;i<=65;i++){// 报表共 65 行,从第 4 行开始设置
document.getElementById(arg1+“0_G”+i).setAttribute(“value”,“true”);// 将值设成 true
_inputSubmit(arg1);// 调用报表保存的 js 函数
}
这样,在页面端点击报表锁定按钮,就能通过 js 更改标识位的值并将值保存到数据库中,再次访问报表时,页面中的数据处于锁定状态,无法编辑。
总结:
至此,完成了客户的所有需求,该例中可以看到,对于数据库结构比较特殊的表,可以通过集算器先对数据进行处理,将处理后的数据返回给报表使用,点击填报后又能在脚本中对数据再次处理,从而实现行列转换的需求,此例中主要是 pivot 函数的使用,具体可以看一下函数说明。并且,润乾填报表页面端的值可以通过 javascript 进行处理,从而实现数据加锁等相应需求。