`
datamachine
  • 浏览: 164016 次
社区版块
存档分类
最新评论

自定义数据源是报表开发的常态

 
阅读更多

报表项目中,大部分报表简单的搞搞即可完成。但是,总有一部分复杂报表需要自定义数据集才能实现。自定义数据集是指报表的数据源不能通过简单SQL实现,需要用报表工具提供的API,调用程序员开发的程序来实现。这部分报表数量不多,但是编程、调试工作量较大,在整个项目中占用的时间反而更长。

为什么自定义数据集会成为报表项目的常态?

 

报表由两部分组成的:数据计算和报表呈现。自定义报表出现的原因,是因为数据库的原始数据结构与报表要展现的数据之间差异大,造成报表数据计算过程比较复杂。

有些报表连接的原始数据库是生产数据库,数据结构不适合报表直接展现,所以要写比较复杂的程序;即使报表连接的是经过整理的数据仓库,其数据结构也不一定能适合所有的报表,特别是项目后期出现的报表,一般都要在数据仓库的基础上做进一步复杂计算才能在报表中展现出来。

 

出现自定义数据源的另外一个原因,是需要连接多个数据库或者其他种类的异构数据源,如oracledb2、My sql和文件等,也需要自定义数据源。

自定义数据源唯一的好处:无论数据源计算多么复杂,数据来自多少个不同的数据库或者文件,只要会写代码、肯写代码,一定能把所有数据集中到一起完成计算。

 

现有的编程手段对自定义数据源没有特别理想的。

 

以Java为例,Java来自定义数据源的工作量较大,难度高,因为Java并没有提供常用类库,我们要耗费大量时间和精力来手工实现细节,包括聚合,过滤,分组,排序,排名等。比如,数据存储和访问的细节:每条数据,每个二维表都需用List/map等对象组合起来,再用嵌套的多层循环来算。这类计算往往涉及到批量数据之间的集合和关系运算,或者对象之间和对象属性之间的相对位置的运算,这些底层逻辑搞起来非常费力。如果还有复杂的有序计算,Java处理的工作量就更大了。

 

举例:某网络平台需要监测一定周期内的用户状况,为运营部门出具日报、周报、月报、年报等报表,每类报表中均包含本期与上期、上上期数据比较。此处以日报为例(月报年报只是统计周期不同),报表格式如下:



 
<!--[endif]-->

报表分为两部分,上半部分为用户明细数据,由于用户较多,报表中只显示按本期在线时长排序后的前十名和后十名;下半部分为本期数据与上期、上上期的比较结果。

 

以润乾报表为例,使用Java来计算自定义数据源的主要代码如下:

获取报表参数

        Map map = ctx.getParamMap(false);

        if (map != null) {

            Iterator it = map.keySet().iterator();

            while (it.hasNext()) {

                // 分别取得参数

                String key = it.next().toString();

                data_date = map.get(key).toString();

            }

        }

 

执行数据库sql取数

            String sql ="select a.userid auserid,a.first_logout_time,b.userid buserid,b.onlinetime bonlinetime,b.account baccount,"

                  +"c.userid cuserid,c.onlinetime conlinetime,c.account caccount,d.userid duserid,d.onlinetime donlinetime,d.account daccount,"

                  +"from"

                  +"(select   v.userid, v.first_logout_time"

                  +"from     t_dw_zx_valid_account v"

                  +"where    v.standard_7d_time is not null) a,"

                  +"(select   userid, sum(onlinetime) onlinetime, max(account)"

                  +"from     t_dw_zx_account_status_day"

                  +"where    logtime >= to_date('"+start_time_tm+"','yyyy-mm-dd hh:mi:ss')"

                  +"and      logtime <"+end_time_tm+"','yyyy-mm-dd hh:mi:ss')"

                  +"group by userid"

                  +"having max(account) is not null) b,"

                  +"(select   userid, sum(onlinetime) onlinetime, max(account)"

                  +"from     t_dw_zx_account_status_day"

                  +"where    logtime >= to_date('"+start_time_lm+"','yyyy-mm-dd hh:mi:ss')"

                  +"and      logtime <  to_date('"+start_time_tm+"','yyyy-mm-dd hh:mi:ss')"

                  +"group by userid"

                  +"having max(account) is not null) c,"

                  +"(select   userid, sum(onlinetime) onlinetime, max(account)"

                  +"from     t_dw_zx_account_status_day"

                  +"where    logtime >= to_date('"+start_time_lm_1+"','yyyy-mm-dd hh:mi:ss')"

                  +"and      logtime <  to_date('"+start_time_lm+"','yyyy-mm-dd hh:mi:ss')"

                  +"group by userid"

                  +"having max(account) is not null) d"

                  +"where  a.userid = b.userid(+)"

                  +"and    a.userid = c.userid(+)"

                  +"and    a.userid = d.userid(+))"

                  +"order by b.onlinetime desc";

 

为降低复杂度,数据初步加工(分组、过滤、排序)仍然使用sql完成。

 

获取列名

            for(int i=0;i<colCount;i++){

                colName.add(rsmd.getColumnName(i+1));//列名

                type = rsmd.getColumnType(i+1);

            }

 

读取表数据,将其存入List

            while (rs.next()) {

                List<Object> rowData = new ArrayList<Object>();

                for(int i=0;i<colCount;i++){

                    rowData.add(rs.getObject(i+1));

                    System.out.println("rowData"+i+"="+rowData.get(i));

                }

                data.add(rowData);

            }

 

构造数据集ds1

DataSet ds1 = new DataSet("ds1");

        for (int i = 0; i < colName.size(); i++) {

            ds1.addCol(colName.get(i));// 设置数据集的字段

        }

        Row rr = null;

 

遍历List计算汇总值

        for(int i=0;i<data.size();i++){

            List<Object> row_data = data.get(i);

            boolean flag1=false;

            boolean flag2=false;

            boolean flag3=false;

            boolean flag4=false;

            boolean flag5=false;

           

            for(int j=0;j<row_data.size();j++){

                Object single_data = row_data.get(j);

                String str_single_data = single_data.toString();

                /****************计算汇总值************************/

                if(j==3 && single_data!=null){//buserid is not null

                    flag1=true;

                }elseif(j==6 && single_data!=null){//cuserid is not null

                    flag2=true;

                }elseif(j==9 && single_data!=null){//duserid is not null

                    flag3=true;

                }elseif(j==2){

                    if(str_single_data.compareTo(start_time_lm)>=0 && str_single_data.compareTo(start_time_tm)<0){

                        flag4=true;//

                    }

                    if(str_single_data.compareTo(start_time_lm)<0){

                        flag5=true;

                    }

                }

               

                if (flag2&&flag3){

                    count1++;  

                }

                if(flag3&&!flag1){

                    count2++;  

                }

                if(flag4){

                    count3++;

                }

                if(flag1&&flag4){

                    count4++;

                }

                if(!flag3&&flag2&&flag5){

                    count5++;

                }

                if(!flag1&&!flag3&&flag2&&flag5){

                    count6++;

                }

            }

 

前十名数据

            if(i<=10){

                // 设置数据集中的数据

                rr = ds1.addRow();

                for (int j = 0; j <row_data.size(); j++) {

                    rr.setData(j + 1, row_data.get(j));             }

            }

        }

 

后十名

for(int i=0;i<data.size();i++){

            List<Object> row_data = data.get(i);

                    if(i>data.size()-10){

                // 设置数据集中的数据

                rr = ds1.addRow();

                for (int j = 0; j <row_data.size(); j++) {

                    rr.setData(j + 1, row_data.get(j));

                }

            }

        }

 

代码已经很长了,加上获取数据库连接、计算前n天和后n天日期的代码会更长。而且,数据的分组排序是数据库(sql)完成的,如果用Java代码量会更大。

 

我们试着用集算器来弄,找刚进组的小孩做。

 

上边的例子,集算器代码如下:



 
<!--[endif]-->

A4-A6:进行数据过滤

A7-A9:按userid分组

A10:将以上结果集进行关联

A11:基于A10进行过滤后按在线时长排序

A12:新序表,用于读取前后十名记录

A13-A14:通过序号分别取前后十名记录

A15-A20:计算汇总值

A22:将前十名、后十名记录以及汇总值分别以不同结果集通过集算器JDBC返回给报表。

 

一个屏幕内搞定整个代码,比较简洁。集算器对有序运算的支持,使得取前后十名(A13、A14)非常容易,不用像Java必须写个循环。报表工具通过Jdbc调用自定义数据源。与Java的API接口比较,Jdbc调用更简单。另外,集算器代码是解释执行的,无需编译,程序升级时替换脚本程序文件即可。

学习成本方面,理解集算器的序表、游标花了点功夫,总体看效果不错。

 

 

  • 大小: 59.5 KB
  • 大小: 74.7 KB
1
0
分享到:
评论

相关推荐

    spring+jpa+atomikos多数据源

    在IT行业中,尤其是在企业级应用开发中,处理多个数据库已经成为常态。"spring+jpa+atomikos多数据源"是一个重要的技术组合,用于构建能够同时连接并操作不同数据库的应用程序。下面将详细介绍这个主题涉及的知识点...

    人流密集场所落实常态化疫情防控措施日报表.docx

    从给定的文件标题“人流密集场所落实常态化疫情防控措施日报表”及文件描述可以看出,这份文档主要用于记录和管理各类人流密集场所实施常态化疫情防控的具体措施及其执行情况。由于该文档涉及多个部门及其管辖的不同...

    报表采集汇总分析项目的关键点.doc

    针对中国报表特有的多数据源、整表规则分片、不完全划分等复杂特征,系统应提供先进的数据统计功能,避免手工准备数据或子表拼接的繁琐工作。 ### 八、支持二次开发 为了满足极个性化的需求,报表系统应支持二次...

    润乾应用开发教程例子

    润乾软件是一家专注于数据可视化和报表工具开发的公司,其产品广泛应用于企业级的数据分析与展示。本教程主要围绕“润乾应用开发”这一主题,旨在帮助开发者掌握如何利用润乾软件进行高效、灵活的应用构建。我们将从...

    S7-400编程实战案例,覆盖了多cpu通讯,pid调节,各种自定义功能块的开发等.rar

    本压缩包文件“S7-400编程实战案例”提供了丰富的实践案例,涵盖了多CPU通讯、PID调节以及自定义功能块的开发等内容,对于深入理解和掌握S7-400编程技术具有极大的帮助。 一、多CPU通讯 在大型工业系统中,多个CPU...

    健康码数据常态化应用的比例原则限制.docx

    ### 健康码数据常态化应用中的比例原则限制 #### 一、背景介绍与问题提出 随着2020年新冠疫情的爆发,全国各地普遍引入了健康码系统作为疫情防控的重要手段。这一系统通过收集个人基本信息、健康状态、出行记录等...

    基于疫情常态化的校园健康大数据分析与应用.pdf

    本项目团队自主研发的校园疫情常态化综合管理大数据分析系统,通过自建云平台搭建数据环境,实现了校园一体化数据同控管理,快速实现了相关人员的健康、生活情况的实时监测,实现了服务数据化,为快速部署、机动反应...

    数据资产管理常态化数据治理实施.zip

    5. **元数据管理**:元数据是关于数据的数据,用于描述数据的来源、含义和使用方式。有效的元数据管理可以帮助理解数据,提高数据的可发现性和使用效率。 6. **数据安全与隐私保护**:遵循相关法规,实施数据加密、...

    建材行业:数据点评:产销回归常态水平,价格依然坚挺.pdf

    建材行业:数据点评:产销回归常态水平,价格依然坚挺.pdf

    用集算器实现跨数据库关联报表

    实际应用中很多报表的数据来源于多个不同类型的数据库,报表数据源跨数据库是报表开发中的常态。目前实现这类跨库关联报表的方式有多种,但都会存在这样那样的问题。  使用报表工具自身多源关联功能  现在大多数...

    数据资产管理常态化数据治理实施z0111.ppt

    "数据资产管理常态化数据治理实施" 数据资产管理是指企业对其拥有或控制的数据资源的管理,旨在将数据资产化,实现数据的价值最大化。数据资产管理的发展经历了三个阶段:初级阶段、中级阶段和高级阶段。初级阶段...

    “认识新常态、适应新常态、引领新常态”组织落实情况汇报 .docx

    - 实施五大抓手:项目开发、数据分析、能力建设、客户服务、风险控制。 #### 五、总结 通过“认识新常态、适应新常态、引领新常态”的系列活动,该公司不仅增强了全体员工对新常态的认识,还制定了适应性的发展...

    常态播放器全.zip

    2. 第三方播放器:由独立开发者或公司开发,如VLC Media Player、PotPlayer、KMPlayer等,通常具有更广泛的格式支持和自定义选项。 3. 在线流媒体播放器:如YouTube、Netflix等,专为在线观看设计。 四、常态播放器...

    开发区开启“三次创业”新征程实现新常态下新跨越.pdf

    【开发区开启“三次创业”新征程实现新常态下新跨越】这一主题着重强调了开发区在新时代背景下的发展方向和战略目标。开发区的“三次创业”是其迈向更高层次发展的关键步骤,主要包含以下几个方面: 1. **转型创新*...

    谈外部报表使用者对现金流量表的数据挖掘.doc

    【摘要】和【部分内容】所述,本文探讨了外部报表使用者如何深入挖掘现金流量表的数据,以获取企业的真实财务状况,并进行有效的报表分析。现金流量表是企业财务报表的重要组成部分,它基于银行信用和收付实现制,能...

    IaaS与PaaS融合是新常态.docx

    IaaS与PaaS融合是新常态.docxIaaS与PaaS融合是新常态.docxIaaS与PaaS融合是新常态.docxIaaS与PaaS融合是新常态.docxIaaS与PaaS融合是新常态.docxIaaS与PaaS融合是新常态.docxIaaS与PaaS融合是新常态.docxIaaS与PaaS...

    新时代新常态下如何有效开发职业教育信息技术类教材.docx

    ### 新时代新常态下有效开发职业教育信息技术类教材的关键策略 #### 一、背景分析 随着信息技术的飞速发展,特别是计算机网络技术和移动通信技术的进步,信息技术的应用领域不断扩大,如大数据、物联网、云计算、...

    中望3D实例教程-自定义BOM.pdf

    在现代制造业中,利用计算机辅助设计(CAD)软件进行产品设计已成常态。中望3D作为一款功能强大的CAD/CAM软件,在工程设计领域中扮演着重要角色。当设计师们在进行复杂装配时,如何高效地展示和管理零件信息,就显得...

    养老机构疫情常态化防控方案.docx

    【养老机构疫情常态化防控方案】 该方案旨在针对新冠病毒疫情的常态化防控,确保养老机构的安全运行。方案遵循“外防输入、内防反弹”的防控策略,强调底线思维、风险意识和问题导向,考虑到无症状感染者和流感可能...

    自定义图像按钮的样式效果源码.zip

    在Android开发中,自定义组件是一项重要的技能,它允许开发者根据设计需求创造出独特且符合应用风格的元素。这个"自定义图像按钮的样式效果源码.zip"文件正是为实现这样的目标而提供的。让我们深入探讨一下如何...

Global site tag (gtag.js) - Google Analytics