﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-广义报表博客-最新评论</title><link>http://www.blogjava.net/blogjava1/CommentsRSS.aspx</link><description>专注于商业智能的发展与进步</description><language>zh-cn</language><pubDate>Thu, 04 Sep 2008 03:30:44 GMT</pubDate><lastBuildDate>Thu, 04 Sep 2008 03:30:44 GMT</lastBuildDate><generator>cnblogs</generator><item><title>re: 新一代报表工具–报表设计的革命[转] </title><link>http://www.blogjava.net/blogjava1/archive/2008/08/11/221303.html#221306</link><dc:creator>挨T守望者</dc:creator><author>挨T守望者</author><pubDate>Mon, 11 Aug 2008 07:18:00 GMT</pubDate><guid>http://www.blogjava.net/blogjava1/archive/2008/08/11/221303.html#221306</guid><description><![CDATA[一、前言<br>　　报表，是应用软件系统中非常重要的环节。<br>　　报表，是用户最容易变化、最可能扩展的需求。<br>　　报表，看似简单，实际往往会占用开发者大量的精力与资源。<br>　　为了解决报表的制作问题，为了提高开发的效率，出现了专门报表工具，从图形界面开始，最早可以算是十多年前VB下面捆绑的Crystal Report了。它的设计模式，至今还是大多数报表工具所采用的基本模式，象Brio, MSTR，Cognos, Style Report, Actuate这些常见的报表工具/BI前端展现工具，无不是基于这一种模式。<br>　　报表工具随着需求的发展、应用开发水平的提高在不断发展，由 C/S结构发展到支持Web报表的方式，出现了许多增强的功能，也出现了大量的新产品，然而，基于传统的模型，只能是改良，报表设计的效率、运行的性能无法取得本质的提高。<br>　　技术的创新总是由需求拉动的。大量的、复杂的报表需求，使得报表工具从技术上出现了一系列的新东西，这已经不仅仅是改良，而是报表工具的一个革命，因为它从报表的根本-报表的设计模型上，进行了根本性的变革。称之为新一代报表工具并不为过。<br>　　以润乾软件为代表的新一代报表工具，其设计模型与传统工具相比，可以用：多源分片、不规则划分、行列对称、动态格间计算这四大特点来概括和理解。<br><br>二、多源分片<br>　　先看一个并不复杂的例子：<br><br>　　实际的业务数据，是分别保存在汽车、房产、土地和其他四个表中的。（在业务数据本身的处理过程中，很可能基于汽车、房产等都还有大量的信息，字段各不相同，因此不可能将这些数据都放在一个表中）<br>　　在传统工具中，实现这个报表的办法，就是先写复杂的SQL语句，形成一个视图：<br>　　select 客户表.客户编码,sum(汽车.抵押金额), sum(房产.抵押金额), sum(土地.抵押金额),sum(其他.低价金额 ) from 汽车,房产,土地,其他 group by汽车.客户编码,房产客户编码.土地.客户编码,其他.客户编码 where (客户表.客户编码 in (select 汽车.客户编码 from 汽车) or客户表.客户编码 in (select f房产.客户编码 from 房产) or客户表.客户编码 in (select 土地.客户编码 from 土地) or客户表.客户编码 in (select 其他.客户编码 from 其他)) and汽车.客户编码=客户表.客户编码 and 房屋.客户编码=客户表.客户编码 and 土地.客户编码=客户表.客户编码 and 其他.客户编码=客户表.客户编码。<br>　　这就是一种单源、不分片的方法，对于这样一个简单的例子，用单源、不分片的传统方法尚可以实现，但是会有很多变化、很多需求（下文会提到），实现起来就更困难甚至不可能了。但就是这张表，做这个复杂的SQL，也是要花点功夫的。更不用说运行时的效率了。<br>　　而在支持多源分片的新一代报表工具-润乾报表中，只需要直接使用几个类似于“select sum(汽车.抵押金额) from 汽车 group by 汽车.客户编码”这样的简单SQL作为数据库，就可以轻松实现：<br><br>　　也就是，在报表中直接使用四个数据源，将报表分成了四片，由于新一代报表工具支持各片之间的动态关联，所以使复杂的问题大大简化了。<br>　　以这个例子为基础，我们可以对多源分片有了一个初步的认识。下面深入讨论一下：<br>　　多源是指一个报表的数据来源来自多个物理数据表（或类似数据体，如视图或其他虚拟表）。这里的“多个”甚至不只是两个三个，而可能是七八个乃至十几个。很多传统报表工具在设计时都可以从多个表中取数据，但实际上还是将这些表通过关联等方式形成了一个单一的数据源，即一个视图。这并不是我们所说的多源，因为在你取字段时，总是来自于这一个视图，即在报表设计前将多源转化成单源处理。而某些传统工具所说的多源，则实际上指的就是多数据库支持，只是把数据库桥功能集成进入报表工具中，但真正到报表设计时仍然是单源的。象上述的多表、多库都不是真正能简化报表设计的多源，只有在进行报表设计时，多个数据源可以独立使用，才是我们所说的多源。<br>　　分片是指报表的纵向或横向（或双向）同时被分成了多个区域，每个区域重复规则不同，而又可能相互运算。许多传统报表工具都提供子报表。子报表可以说是某一种分片的方法，但是子报表与主报表并非一个整体，不能互相运算。而我们所说的分片，是各片处于一个统一的报表当中，可以互相运算。<br>　　多源与分片是紧密相关的，往往分片后不同片需要使用不同的数据源。<br>　　在出现多源分片这一新技术前，传统工具对于这种表中不同部分的数据来自不同数据源的分片问题的解决方案是：<br>　　- 对于报表的水平方向上的几片，可以做成一个统一的视图，或者写存储过程、或者写程序准备数据。<br>　　- 对于纵向上格式与内容的变化，可以用子报表。（因为格式不一样，光用UNION准备数据是不行）<br>　　然而，问题在哪里呢？<br>　　做统一的视图（单源），会产生两大问题：<br>　　1． SQL的复杂程度：横向分片，需要JOIN；如果纵向也有分片，则需要JOIN+UNION。那么，如果数据来自于五六个数据源呢？这个SQL怎么写，既需要水平，也需要时间。<br>　　2．运行效率：就算你写出了SQL，能够做出来这张表，但实际运行时的效率会怎么样呢。如果是三张表做JOIN，复杂度就是O(Nk)。<br>　　当然，还可以写存储过程（带来移植方面的问题）、写代码，通过分步计算来避免复杂的SQL，通过预先准备数据来解决运行效率问题……，但是，相应会带来对开发效率的巨大影响。<br>　　子报表，应该说也能解决一部分问题（主要是纵向的。横向上子报表基本没有用），因为从理论上毕竟子报表可以使用与母报表独立的数据源。但是，子报表也存在着若干问题：<br>　　1．各个子表各自为政，主表或某个子表的格式进行了调整，所有其它子表都需要改动，这是极其繁琐的工作。<br>　　2．在数据上，主子表之间和子表相互之间都无法沟通数据，只能将主表的数据作为参数传递给子表，子表无法带回信息，也无法向其它子表提供信息。这时，整表的混合运算将非常困难，必须单独计算，无法采用某些子表的中间运算结果，不仅书写复杂，运算效率也降低。<br>　　这是一个标准的主子报表（主从报表），其中下面的产品明细行部分是用子报表实现的：<br><br>　　但是要注意，在主表中出现了金额这一项。这个数据实际是来自于子报表中的数据合计。但是，由于子报表无法将数据传递给主报表，所以解决起来就只能用另外的方式在主报表中把这个数计算出来。如果有多个这种数据项（比如数量的合计之类的），实现起来就更复杂了。这还只是一个标准的主子报表的情况，实际会有更多更复杂的格式与数据关联的情况，是拿子报表很难实现的。<br>　　对于传统工具的这些困难，采用多源与分片的技术，则可以迎刃而解。做起来非常复杂的表，可以应用多源分片技术轻松完成。<br>　　不仅对于那些用传统工具非常复杂，但是还是“能做”的表，可以应用多源分片大大提高开发与运行效率，并且对于许多传统工具“不能做”的表，更是可以通过新的模型来轻松解决。<br>　　下面我们就看一个来自于实际业务中的真实报表：<br><br>　　这个表是个典型的纵向分片报表，数据区从上至下分成了几片，先是一片按客户汇总的两级分组区域，然后是两个固定计算行，接下来又是一片按年度汇总的一级分组区域，最后又是一个固定的合计行。各片分组层数不同，而且变动与固定固定结合，而且各片之间还有数据沟通（某些计算行的值是由其它行计算出来的）。这种上下格式都不一致的报表，其数据源是不可能组织成单源的（各片列数不同），也就不可能被传统工具实现<br>　　而采用新一代报表工具的多源分组模型，实现起来则是很轻松的：<br><br>三、不规则划分<br>　　传统报表工具中，很典型的就是数据分组。例如：<br>　　省份<br>　　城市<br>　　显示出来就是：<br>　　山东<br>　　济南<br>　　青岛<br>　　山西<br>　　太原<br>　　大同<br>　　相信很多报表的开发者都对这些很熟悉。<br>　　这种分组都是完全规则划分的，即划分标准一致且有规则（一般都按某个字段或表达式），所有事实都必须出现且只出现一次，分组值次序与原数据记录次序一致。<br>　　与完全划分相对应，在报表汇总中却常常需要不规则划分，即划分标准看不出规律（常常只能穷举），所有事实不一定全部出现在分组结果中、个别事实还可能重复出现，次序也与原数据记录无关。<br>　　我们看一个例子：　　<br>　　这个报表用传统工具实现很困难，青岛的数据是山东的数据的一个子集，虽然报表格式并不复杂，但由于出现了不规则划分，无法直接用报表工具的分组功能完成，只能编程把数据准备成一个单层的二维表数据源，既加大了工作量，又很难体现数据之间的层次关系。(如可将“其中：石家庄”靠右呢，体现数据的层次关系)<br>　　在新一代报表工具中，上例的实现就要简单得多：<br><br>　　在润乾报表中，我们可以使用两个数据集ds1和ds2在表格上的关联来完成这张表的定义。通过内建数据集或list函数，将地区按照需要的顺序排列出来。内建数据集编辑界面如下：<br><br>　　为了突出河北和石家庄的从属关系，我们还可以在字段中加入空格来体现。通过定义C5格中的表达式为= ds1.sum(贷款余额,地区=B5) 将C5格的数据和B5的地区进行关联。<br>　　再看这张表，使用过Crystal Report的开发者可以想一想如何实现：<br><br>　　这里面涉及了不完全分组（年龄段并未覆盖全部的，你怎么把&lt;20的隐藏起来呢？）<br>　　新一代报表工具，则对不规则分组给予了良好的支持，使得很多这类问题能够轻松解决。<br> <br>四、动态格间运算<br>　　所有的报表工具都会提供一些计算列的功能，在原始数据基础上再计算出一些别的列值或统计值，这是报表展现中是不可缺少的功能。但是，传统工具在计算上的机制是有局限的：<br>　　1．传统工具一般只提供同行内的格间运算和针对某组（或全体）的集合运算，对于常见的跨行组运算则相当困难。<br>　　2．个别传统工具提供了简单的跨行能力，如可以引用上一行数据，而跨组则无能为力。<br>　　3．对于集合运算只提供个别固定的函数，如取第一名、算累计值等，无法组合出的通用集合运算则无计可施，如取第二名、算累计的乘积等。<br>　　4．某些带条件的运算更是无法可想，如计算语文成绩在90分以上的同学的数学成绩总和。<br>　　5．除了有规律的跨行组运算外，报表中还可能会有一些随意的独立格运算，其值可能是报表中的任意几个其它格运算出来，甚至还可能会引用到报表外的数据（比如和数据库中的数据再次运算等），这些都很难实现。<br>　　这些问题的根据原因在于，传统工具没有很好的运算后报表数据命名机制（传统工具只能用列名命名设计阶段的数据单元），很难精确描述数据引用关系，只能写出规律性很强的表达式，但随意的独立格运算会就使传统工具无法处理，而报表外的数据引用更是只能借助脚本或外围应用程序，导致代码极为混乱。而在具有动态格间运算的新一代报表工具中，就可以更加灵活地处理很多报表中的运算问题，可以不受上述种种限制，灵活地进行计算。并且，这种计算不仅可以随意地在数据格间进行，还可以在有数据展开的情况下进行动态的引用。<br>　　我们看两个典型的例子：<br><br>　　上表是个典型的跨行组运算报表，其中有比上期（跨行）和比去年同期（跨组）运算，这种报表在传统工具中常常必须编程准备数据。<br>　　再比如：<br><br>　　展现了另一些动态格间运算，如计算排名，需要在同组中数出比当前值大的数的个数。下方的几个独立格中又引用了表格中数据，但又非整组全部引用，而是带了某种条件（前三名），最下方的一个格中还会引用到报表外的数据（北京市的全部销售额不在报表中）。<br>　　这两个报表的样式都不复杂，但这些格间运算会让传统工具非常为难，只能再次依靠程序代码，把数据事先计算好直接往报表里填。而在新一代报表工具中，采用动态格间计算的方法，实现起来将非常简单：<br><br>　　在计算排名时，C4格使用动态层次坐标表达式=count(B4[`0;`0]{B4&gt;$b4})+1算出当前排名。<br>　　　　在统计部分，简单的使用了统计表达式的数据过滤来完成，如=sum(b4{c4&lt;=3})，计算排名号码在3（包含）一下的销售额，即总计。 <br> <br>五、行列对称<br>　　看一看这个例子：<br>　　张表在纵向上并不复杂，相信对于Crystal Report或者其他许多类似的产品是很容易的。但它在横向上有两个难点，一是列不固定，实际是按数据进行了扩展，就如同典型的分组报表在纵向上的方式一样，二是内容复杂，并不是简单的、标准的两层分组。<br>　　这种报表很典型，然而传统工具对此几乎无能为力。<br>　　这是因为传统工具本质上来源于纵向分组模型，即行式表，先是解决打印数据表的问题，然后根据需要又加上了分组、合计等等，但其行列严重不对称，列方向能力远远弱于行方向，列一直是固定的，完全不支持列向变动。<br>　　而对于在横向扩展数据列的需求，传统工具提供了交叉表的方式。但是，交叉表非常死板，虽然可以支持多层变列，但只能有一片变列区，而且其中的汇总运算很简单，只有固定的一些函数，不可随便增加运算行列。象上面那个例子，在水平方向的展开并不是标准的先列数据再小计的方式，用交叉表实现起来就会很困难，假如再增加一列“与去年同期比”之类的，交叉表就更束手无策了。<br>　　新一代报表工具则采用了行列对称的模型，纵方向上拥有的能力与功能，完全可以在横方向上实现，彻底解决了上述问题。象我们所举的例子，在采用行列对称的模型的新一代报表工具中实现起来就会轻松得多。<br><br> <br>六、结语<br>　　根据以上介绍，我们可以看到，正是由于报表需求的复杂性，使得基于传统模式的报表工具在处理很多报表时有较大的难度，面对一个个新的问题，可能出现一个个新的对应办法，分组、公式、交叉表、单元格合并、表格式设计器……，但这实际只是一种不断“补”的方法。事实上，同一张报表中很可能包含了多种的问题，当这几种困难交织到一起时，整个问题的复杂度要远比解决几个单个问题的总和要大得多。这要求我们给出完整的解决方案，而不能单独分别处理。改良是必要的，但光是改良是不够的。<br>　　而报表工具的新的发展，是革命性的。它不仅仅是改良了报表工具的功能，更从根本上变革了报表的设计与实现方法，使原来复杂的事情变得简单，使原来不可能的事情成为可能，从而大幅度降低了报表设计的成本，提升了报表系统的性能，这才是报表系统的开发者所最关注的核心问题。<br>　　令人欣慰的是，基于上述新型模型的新一代报表产品-润乾报表，已经为很多开发商和用户应用。许多原来困扰于复杂报表制作的客户，已经从报表工具的革命中获益。新一代报表产品的实践，也证明了技术革命将能大大地为用户带来效益。<br>本文出自 51CTO.COM技术博客<img src ="http://www.blogjava.net/blogjava1/aggbug/221306.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/blogjava1/" target="_blank">挨T守望者</a> 2008-08-11 15:18 <a href="http://www.blogjava.net/blogjava1/archive/2008/08/11/221303.html#221306#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>