布局格式
横向分栏
大多数报表工具都支持纵向分栏,但几乎没有报表工具支持横向分栏,我们可以用集算器把数据集事先摆好。
| A | B | C |
1 | =db.query("select a,b,c from T ") | ||
2 | =A1.step(3,1) | =A1.step(3,2)|[null] | =A1.step(3,3)|[null] |
3 | =A2.derive(B2(#).a:a2,B2(#).b:b2,B2(#).c:c2,C2(#).a:a3,C2(#).b:b3,C2(#).c:c3) |
这段代码将3列结果集(a,b,c)横向拼接成9列结果集(a,b,c,a2,b2,c3,a3,b3,c3),行数是原来的1/3,报表工具按普通报表方案处理即可实现横向3栏的效果。
补齐空行
报表在打印时要将每页充满,最后一页如果行数不足满页需要补足空行,而许多报表工具本身未提供这个功能。用SQL在数据集上补足这些行并不容易,用集算器很简单。
| A |
|
1 | =db.query("select * from T") |
|
2 | =pn-A1.len()%pn | 计算应补的行数 |
3 | =A1|if(A2!=pn,A2*[null]) | 补充空行数后的结果集 |
将每页显示的行数pn作为参数传递进来。
交叉表列运算
如下的报表,统计某年(作为参数)及其去年的产品销售额和增长率
产品 | 2014 | 2015 | 2015增长率 |
空调 | 100 | 120 | 20% |
电视 | 200 | 210 | 5% |
… | … | … | … |
数据结构简化为 产品、年度、金额。
这看起来象个交叉表,但最后一列的增长率涉及到列间运算,而一般报表工具对交叉表只提供列间的统计式计算(如求和、平均等)。如果不用交叉表则需要事先将数据做转置,而且又会涉及许多报表工具不支持的动态列名功能。
如果用集算器将增长率计算出来后补入原始数据,就可以用常规交叉表实现了。
| A | B |
|
1 | =db.query("select 产品,年度,金额 from T where 年度=?-1 or 年度=? order by 产品,年度",Y,Y) | Y为参数年度 | |
2 | for A1.group(产品) | >A1.insert(0,A2.产品, string(Y)+"增长率", string(A2(2).金额/A2(1).金额-1,”#%”) ) | 计算增长率后插入 |
3 | return A1 |
|
|
过程计算
避免隐藏
列出销售额占了前一半的大客户名单和金额以及这些客户的数量和平均销售额,数据结构简化为客户、金额。
这个运算有明显的步骤,先按金额将客户排序,同时计算出金额合计,然后在客户列表中计算累计金额,达到一半总额时其它的记录将被过滤掉。
在报表工具中很难直接实现这个步骤。报表是状态式计算,即把所有表达式填入后,由报表工具自动识别依赖关系后决定计算次序,要人为控制计算次序,就要设计合理的单元格引用关联,其中的中间结果还需要用隐藏格实现。
以润乾报表为例的实现方法:
ds=select 客户,金额 from 客户销售 order by 金额 desc
| A | B | C |
1 | 客户 | 金额 | =ds.sum(金额)/2 |
2 | =ds.select(客户) | =ds.金额 | =C2[-1]+B2 |
3 | 大客户数量 | =count(B2{C2[-1]<C1}) |
|
4 | 平均销售额 | =avg(B2{C2[-1]<C1}) |
|
C列要隐藏,并且在第2行设置显示条件为C2[-1]<C1。和表中的表达式类似,这里都要使用C2[-1]<C1来处理刚好跨过一半销售额的那一行,而不能用更简单的C2<=C1。
从报表设计中可以看到,这个条件会被重复计算多次。而且,被隐藏的小金额条目要比大金额条目更多,造成内存空间没必要的浪费。虽然报表可以做出来,但编写理解难度较高,并且运算效率很差。
另外,这个报表用到了跨行运算和格集条件过滤以及按条件隐藏行等功能,润乾报表对这些复杂的计算有着良好的支持,但并非所有报表工具都是这样,采用计算能力较弱的报表工具,这个报表就很难直接开发出来了。
如果采用集算器先准备出数据源再做报表,整体过程就清晰很多。
| A | B |
1 | =db.query(“select 客户,金额 from 客户销售 order by 金额 desc”) | |
2 | =A1.sum(金额)/2 | =0 |
3 | =A1.pselect((B1+=金额)>=A2) | return A1.to(A3) |
在集算器脚本中实现前述的步骤,虽然代码也有几行,但完全按自然思路,很容易理解和编写。脚本只返回符合条件的大客户,拿到这个数据集,使用普通报表工具都可以采用常规方案简单实现了。
过程计算
有些涉及到单元格位置改变的过程性计算,即使愿意付过编写困难和运算效率的代价,也难以用隐藏格实现。
比如将分组后按汇总值排序,这不算很罕见的需求,但许多报表工具无法直接实现。报表的排序功能大都设计在分组之前(因为更常见),没有分组后的排序。使用集算器脚本就很简单,代码具有足够的灵活性,可以描述各种计算次序的要求。
| A |
|
1 | =db.query(“select …”) | 取出数据 |
2 | =A1.group(G).sort(~.sum(A)) | 按G分组再按A的合计排序 |
3 | =A2.conj() | 合并成单层集合返回 |
这个脚本返回的结果集已经按分组汇总值排过序,报表工具拿到数据后只要简单再分组重新计算汇总值就可以了。
类似地,如果上小节例子中我们希望那些大客户按名称排序而非销售额,使用报表工具几乎就无法完成了。而使用集算器只要把B3格表达式改成A1.to(A3).sort(客户)。