报表引擎 - 报表应用思路

  OpenExpressApp计划之内包括一个报表引擎OpenReport。2006年时在公司负责研究并实现了一个报表引擎,写了几篇博文(《交叉表的报表设计》《研究润乾报表的实现》《使用Antlr实现表达式引擎》)。OpenReport的报表模型将会和我已经实现的差不多,但是有些主要差别就是,OpenReport除了支持数据集,还可以基于对象,在设计器上和使用上将会更易用更方便,会更多考虑业务人员的使用和一些BI。但是实现起来会花更多时间和精力,而现在我的精力毕竟有限,所以还没有开始OpenReport的工作,目前OEA主要还是集中在应用框架上。

   现在还有人看到我以前的两篇和报表相关的博文并非常感兴趣,但由于那个报表引擎不是开源产品,所以不能公布代码,在这里我就将以前写的一些文档发布一下,给那些需要或者感兴趣的人借鉴一 下。我之前也是看了别人的一些文档而作出来的这个报表引擎,所以研究报表引擎的看完这些文档之后应该就会有大体感觉。

  这个系列将会发布多篇,感兴趣的可以留意一下。本篇为第一篇,将从总体上介绍一下报表应用思路,这是我2006年1月份在刚开始研究报表几周后写的。就像很早以前博文《研究润乾报表的实现》所说,这里的模型主要是参考润乾报表的,我觉得它是我研究时期看到的最好的模型。现在润乾有一个免费版本快逸报表,强烈建议研究报表的去用一下,对项目有需求的也可以直接用,在这里也希望润乾报表能做的更好更易用。

提出问题

    报表对于任何管理软件来说都是必不可少的一项主要功能,对于成本管理系统来说企业对报表的要求也逐渐加强,现有公司的报表控件已经在功能和开发效率上不能完全满足要求,希望通过分析能够提出改善的报表解决方案,在能够满足客户需求的情况下再尽量减少开发人员的工作量,并提高软件的质量。

前期

    通过两周时间,收集了一些软件公司的报表软件,分析了一下水晶报表、SAP程序报表以及国内的一些报表厂商的软件,如润乾软件、博易智软等。分析后觉得润乾报表的思路比较好,后期主要针对润乾报表的一些思路进行分析。以下将把主要思路罗列出来,可以作为后期深入的参考。

报表引擎带来的好处

  1. 分离报表实际业务数据和展现形式,只需准备源数据,后续数据展现工作由报表引擎来完成。比如一些小计行,字段合并,大小写等都不应该写在SQL语句中
  2. 采用多源分片和动态格间计算技术能够高效的完成复杂报表工作,缩短产品开发周期,提高产品质量
  3. 通过提供的业务对象和简单的SQL语句构造向导,可以让业务人员制作简易报表
  4. 考虑数据上报功能,系统解决项目和公司的数据来往业务,不需要给每个公司报表另单独做一个模块
  5. 原来单据中编码会夹杂报表功能代码,报表引擎可以分离报表和实际单据业务功能,使得模块功能更清晰,可维护性更高
  6. 提供报表推拉模式,可以由用户订阅关心的报表,使得能够方便的查看需要的数据
  7. 通过提供保存查询条件的功能,可以使得公司负责人员打开报表就能看到预期的结果,免去重复性的输入

以前不能满足的部分功能

以下简单罗列了在以前在XXX系统不能很好解决的几个问题,未收集造价产品的需求:

  1. 颜色警告控制需要代码编写:在相应格子的颜色属性的表达式设置可以解决此问题
  2. 通过查询条件的设置来设定数据显示列的是否显示:通过交互报表的设计,在相关列上的Visible属性上输入与选择条件相关的表达式
  3. 动态列:报表引擎提供横向扩展和纵向扩展,解决动态列将是非常简单的一件事情
  4. 需要小计、合计功能:采用动态格间计算,对于小计和合计等功能非常简单的就能设计好
  5. 主细表的报表需要编写代码完成:通过报表引擎的交互报表解决或者使用树型支持变通报表样式解决
  6. 不能对展现后的数据进行过滤,组合操作:在报表控件中添加对本地报表缓存数据的处理,提供过滤组合功能
  7. 数字大小写:通过提供字符串和数字表达式等在格子显示值中进行转换轻易解决
  8. 对于公司级要求的报表都是定制开发单个模块:如果考虑上报功能,可以统一解决此类问题

建议

  1. 在VSS的专题研究\报表\行业软件\润乾软件\runqian_report下有一个《单位领料明细汇总查询》的示例,以前做此单据不算维护工作量也需要三四天的时间,如果按照此思路完成报表工具, 对于熟悉产品的开发人员在半天就能准确的完成此报表,而且可维护性高。 虽然未考虑全面,但从目前来看,此思路在整体上较好,方案也是可行的。
  2. 润乾报表为Java产品,选择条件面板支持不够,还未发现较好的商业报表产品可以购买,建议公司自主开发。
  3. 报表功能整体涉及面较大,但每部分在我们业务都是需要的,建议公司安排有报表经验的专人深入分析后分步骤开发,先完成下文主要技术中说明的几个问题。 

存在风险

  1. 此文档主要涉及报表数据相关的一些概念部分,对于报表整个系统还未考虑完全。
  2. 只参考了几个查询模块,未深入考虑具体情况,比如通过查询条件构造内部SQL语句的执行、报表交互的控制和扩展、表达式的解析以及上报系统的深入分析,具体深入后可能会发现其他问题。
  3. 开发时间可能会和XXX4整体进度冲突,如有冲突需要另考虑XXX4报表的过渡方案

主要思路

范围

    报表在系统中分为两类:仅供用来查询显示的报表和提供上报公司的报表。目前主要争对查询类分析,对于上报类也将涉及部分。如未显示说明,以下所说的都争对的是查询类分析。在报表使用方面,主要争对报表设计上,本文档不包含系统对报表的管理,比如报表的权限、报表的目录层次等。

    文档将涉及普通报表、交互报表制作以及选择条件的一些思路。

争对用户

主要争对开发人员,提高开发效率和软件质量。在不考虑效率的情况下允许业务人员制作大量简易报表,遇到效率问题和复杂报表时仍由开发人员完成。

  1. 开发人员:报表开发完成后,通过报表设计完成目前所有的查询界面。减少大量组合SQL语句的编写,提高软件质量。分离表现和业务关注点,使开发人员关注业务数据的获取。
  2. 实施人员:经过培训可以完成复杂的报表
  3. 业务人员:可以自己完成中等复杂的报表

报表类型

采用多源分片、动态格间计算主要技术,使用类似Excel的Cell样式进行报表数据的展现。后续会说明这几个技术的概念。

报表制作方式

  1. 报表设计工具:大部分的报表工作都在这里进行。系统默认提供网格、交叉、分组样式
  2. 编码:对于前期没有考虑不能使用报表工作制作的报表

主要技术

  1. 报表引擎
  2. 表达式解释
  3. 控件开发
  4. 脚本语言扩展

以下主要争对报表引擎本身进行说明(多源分片和动态格间计算主要参考的是润乾报表的思路)。

多源分片

    结算、支付、合同费用类型、单位等数据都存放在不同表中,传统开发中是在服务器端通过连接或者Union来构造复杂的SQL语句。这是一种单源不分片的方法 ,在涉及表多的时候会带来两大问题:

  1. SQL的复杂程度:横向分片,需要JOIN;如果纵向也有分片,则需要JOIN+UNION。如果数据来自于五六个数据源,写这个SQL就需要水平和时间,也不利于维护
  2. 运行效率:涉及多张表时,就算复杂的SQL正确的写出来了,但由于JOIN和编写SQL的写法,实际运行时的效率比较低

  

  多源是指一个报表的数据来源来自多个业务实体对象(物理数据表或视图等)。这里的"多个"甚至不只是两个三个,而可能是七八个乃至十几个。在报表设计时使用的也是多个数据体,而不是通过合并后的一个数据体。对于上图示例可以通过以下的报表设计获取:

合同单据: select * from HT_HTDJ           单位字典: select * from XT_DWZD        结算单:select HTID, JE from JSD         支付单:……

  

A

B

C

D

E

1

单位名称

发生金额

累计结算

累计支付

费用类型

2

合同单据.group(乙方标识) 

[显示值表达式: 单位字典.select(单位名称, DWID=@value)]

  

结算单.sum(JE,true,合同标识 in 合同单据.select(合同标识, true,乙方标识 =A2))

  

  

    通过获取简单的几个表,然后再设计器中通过设定格子的扩展、值表达式和显示表达式,即可完成这张报表。合同单据、单位字典等SQL语句可以通过系统的业务对象获取,还起到复用作用,在不破坏报表的情况下,当需求更改时只需要更改业务对象本身即可。

    分片是指报表的纵向或横向(或双向)同时被分成了多个区域,每个区域重复规则不同,而又可能相互运算。许多传统报表工具都提供子报表。子报表可以说是某一种分片的方法,但是子报表与主报表并非一个整体,不能互相运算。这里说的分片,是各片处于一个统一的报表当中,可以互相运算。

    XXX3中对于主表汇总细表金额都是在外部计算好后以宏的方式传入报表,不能在报表本身设计。在多源分片的概念下,将可以设置合计格子的表达式,通过细表的明细汇总出金额。

    对于数据源的定义,可以通过一个数据库SQL语句生成器来生成简单的SQL语句。选择条件(过滤语句)可以在SQL语句中指定,也可以由报表引擎自动根据条件选择设置下推到数据库。(此问题我还未仔细考虑,只是粗略的想法)

动态格间计算

    所有的报表工具都会提供一些计算列的功能,在原始数据基础上再计算出一些别的列值或统计值,比如小计合计等。这是报表展现中是不可缺少的功能。但是,传统工具在计算上的机制是有局限的:

  1.传统工具一般只提供同行内的格间运算和针对某组(或全体)的集合运算,对于常见的跨行组运算则相当困难。

  2.个别传统工具提供了简单的跨行能力,如可以引用上一行数据,而跨组则无能为力。

  3.对于集合运算只提供个别固定的函数,如取第一名、算累计值等,无法组合通用集合运算,如取第二名、算累计的乘积等。

  4.不能实现某些带条件的运算,如计算语文成绩在90分以上的同学的数学成绩总和。

  5.除了有规律的跨行组运算外,报表中还可能会有一些随意的独立格运算,其值可能是报表中的任意几个其它格运算出来,甚至还可能会引用到报表外的数据(比如和数据库中的数据再次运算等),这些都很难实现。

  这些问题的根本原因在于,传统工具没有很好的运算后报表数据命名机制(传统工具只能用列名命名设计阶段的数据单元),很难精确描述数据引用关系,只能写出规律性很强的表达式,但随意的独立格运算会就使传统工具无法处理,而报表外的数据引用更是只能借助脚本或外围应用程序,导致代码极为混乱。而在具有动态格间运算的报表中可以更加灵活地处理很多报表中的运算问题,可以不受上述种种限制,灵活地进行计算。并且,这种计算不仅可以随意地在数据格间进行,还可以在有数据展开的情况下进行动态的引用。

    对于以下示例,表尾需要进行统计,如果在以前的报表中处理则一般是先通过程序编码计算累计值,然后通过宏传入报表。

 

 

    在有格间计算的报表工具中,实现起来将非常简单。在计算排名时,C4格使用动态层次坐标表达式=count(B4[`0;`0]{B4>$b4})+1算出当前排名。在统计部分,简单的使用了统计表达式的数据过滤来完成,如=sum(b4{c4<=3}),计算排名号码在3(包含)一下的销售额,即总计。设计如下:

  

条件选择窗体

  1.  选择参数,允许用户输入单值,程序可以根据该值进行选择
  2. 复杂选择标准: 可以包括范围、操作数、选择条件(大于、小于、大于或等于等)
  3. 定义输入帮助和搜寻帮助(比如选择材料按F4则出现一个下拉材料列表以便选择)
  4. 保存选择条件,以供下次运行程序调用或者直接使用存储参数调用报表
选择条件元素格式化
  1.  参数格式化:缺省值、是否必须、输入值检查、是否显示等
  2. 其他元素:空行、下划线、注释文字
  3. 调整元素位置

交互报表功能

系统需要的报表可能不只是用来查看,还需要一些交互功能。比如

  1. 报表钻取功能,可以在一个报表调用另一个报表或者系统的单据
  2. 报表内部交互,比如切换材料的单位等。或者同一报表有一个材料类别列表,切换后显示相应类别下的材料信息等。
  3. 报表查询结果和选择窗体的交互,比如根据报表选择窗体的设置来设定报表的显示样式等

设计说明(主要从一些概念来说明)

基本概念

  1. 单元格:报表由行列整齐的格子组成,这 些格子我们称为单元格,所有的单元格组成了报表。类似于Excel的每个格子
  2. 合并单元格:多个连续的单元格通过合并操作后显示为一个大的格子,合并后的格子成为合并单元格
  3. 单元格数据类型:支持普通文字、统计图、图片字段、图片文件、子报表、空白单元格、HTML文本
  4. 单元格属性的属性值和表达式:单元格的每个属性都有属性值和表达式两种(属性值和表达式之间互斥,定义了属性值,就不必定义表达式,定义了表达式,就不

    必定义属性值)。属性值是在编辑报表时就写死了的,在报表运行时不必经过运算,也不会被改变,而属性的表达式在报表运行时,会被运算,该属性的最终属性值

    取决于表达式的运算结果值。在属性表达式中可以用"@value"来引用单元格的数据值。
  5. 数据集:可以是一个SQL语句定义的二维表,也可以通过业务对象获取(比如材料字典、入库单等)
  6. 参数:获取数据前用来过滤报表数据的元素,实际上作用在SQL语句的where或参数中。参数有数据类型、可以有缺省值和其他格式设定等。参数可以在数据集和表达式中被引用。
  7. 宏:宏代表没有数据类型的一个字符串,在报表运算时将用宏值替换宏变量所占的位置。可以在报表中任何位置引用宏变量,如单元格值、表达式、数据集定义、单元格属性表达式中等,引用方法为${宏变量名}

推荐:你可能需要的在线电子书

我的微博:http://weibo.com/openexpressapp

敏捷个人sina围裙:http://q.t.sina.com.cn/135484    

欢迎转载,转载请注明:转载自敏捷个人网站

 

posted on 2009-11-14 09:55  周 金根  阅读(5844)  评论(7编辑  收藏  举报

导航