杰表 .2008  报表实例研究 杭州杰创软件拥有版权 .www.jatools.com
现存问题 复杂交叉报表困难 不能同期比 不能交互式排序 不能折列操作
复杂交叉报表困难 表头不平衡 同列不同行
同列
 
行固定 , 列跟随
 
原因分析 模型缺陷 无状态 ->  不能随时得到数据 , 数据模型生命周期 , 不清晰
Model 的生命周期 Model 分为无状态 , 有状态两种 无状态 服务器端不保存 , 适合数据量大 , 不需要动态互的报表 , 比如 , 资产负债表 有状态 服务器端缓存 , 适合数据量小 , 需要动态分析的报表 , 如 olap, 销售分析
有状态数据模型生命周期 初始化 在启一个报表任务时 , 由报表负责初始化 服务 向报表引擎提供服务 , 包括初始化 , 动态交互 , 数据模型可能为多个报表任务提供服务 销毁 当 session 结束时 , 自动从内存中销毁
无状态数据模型生命周期 初始化 在启一个报表任务时 , 由报表负责初始化 服务 为一个报表任务提供服务 销毁 在一个报表任务结束时销毁
Model 语言 原数据类型 所有可用的 java 类型 , 包括  Integer,String,Double,Float,BigDecimal  等
Model 语言 节点类型   单元 , 行 , 列 , 表格 表格 单元 // 数据源 / 班级 /@ 班长 列 // 数据源 / 班级 [0] 行
单元节点引用 行节点 \@ 列名     dataset\ 年度销售表 [0]\@ 销售额 表 \@ 列 [i]     dataset\ 年度销售表 \@ 销售额 [0] @ 列     @ 销售额
单元节点运算 取决于值类型的运算     单元节点 , 根据其数值类型 , 可以使用相应运算 , 比如代数运算 , 及方法 如  String  类型 \\ 系统变量 \$$user.indexOf(“admin”); 如  int 类型 \\ 数据源 \ 学生 [0]\@ 年龄 +100
行节点运算 \,  取列值 班级表 [0]\@ 班长  // ” 班长”列值
列节点运算 ( 一 ) sum,min,max,avg,count 班级表 \ 学生表 \@ 分数 .avg()  //  求平均分数 班级表 \ 学生表 \@ 分数 .max()  //  求最高分 group( 按升序分组 ),group_desc( 按降序分组 ) 销售表 \@ 客户 .group()  //  取客户列表 , 注 : group()  所得结果 , 也是列节点类型 , 因此可用列节点的运算 , 比如 , 销售表 \@ 客户 .group().count(),  //  取客户数 order( 按升序排序 ), order_desc( 按降序 ) 班级表 \ 学生表 \@ 分数 .order_desc()  // 按分数从高到底排序   注 : order()  所得结果 , 也是列节点类型 rank( 按升序排名 , 数值大的 , 名次在后 ),rank_desc( 数值大 , 名次靠前 ) 班级表 \ 学生表 \@ 分数 .rank_desc()  // 按分数越高 , 名次越前
列节点运算 ( 二 ) [i]  求某一位置单元值 , 班级表 \ 学生表 \@ 分数 [2]  //  第三位置的分数 last() ,first()  求首尾的值 班级表 \ 学生表 \@ 分数 .last()  //  最后一个分数 seg(c1,c2,c3,... as v1,v2,v3...), 分段函数 @ 分数 ={50,55,80,90,99,30,70,65} // 60 分以下为差 ,85 以下 , 为良 ,85 分以上为优   x =  班级表 \ 学生表 \@ 分数 .seg(<60,<85,>85 to “ 及格” ,” 良” ,” 优” ) ;  //  经过上述运算后 , 所得结果为 // x ={“ 差” ,” 差” ,” 良” ,” 优” ,” 优” ,” 差” ,” 良” ,” 良” } 注 : seg()  所得结果 , 也是列节点类型
表节点运算 ( 一 ) 取某一行 ,[i], last() ,first()  班级表 \ 学生表 [2]  //  第三行 班级表 \ 学生表 .last()  //  取最后一行 选择 ,select 学生表 .select(@ 学生名 ,@ 年龄  as age, @ 助学金  * 0.09 as bonus); //  返回表节点 过滤 ,[] 学生表 [@ 学生名 .startWith(“ 王” )]  //  取得所有姓”王”的记录 ,  返回类型 , 表节点 增加列 ,addcol 学生表 .addcol(@ 分数 .rank_desc() as  排名 );  //  增加分数排名列 销售表 .addcol(@ 单价  * @ 数量  as  金额 )  //  增加金额列
表节点运算 ( 二 ) rows/count,columns, 取行数 , 列数  班级表 .rows()  //  取行数 , 也可使用  count() 方法 班级表 .columns()  //  取列数 /, 取子节点  销售额 /@ 销售额  //  取销售额 班级表 / 学生表  //  取学生表子节点 cross_select(), 取得交叉数据表 学生表 .cross_select([@ 年度 ,@ 季度 ],[@ 地区 ],[@ 销售额 .sum()]); //  返回交叉表
交叉表运算 交叉表由 cross_select 方法得到 x=cross_select([@ 年度 ,@ 季度 ],[@ 地区 ],[@ 销售额 .sum()]); //  返回交叉表 取得轴表 ,axis0,axis1  x.axis0()  //  得到第一轴表 x.axis1()  //  取第二轴表 measure(), 取得度量表 x.measure()\@ 总销售 ; //  取得总销售
同期比示例 -50 1250 2004 100 1300 2003 200 1200 2002 - 1000 2001 比去年同期新增 ( 万元 ) 销售额 ( 万元 ) 年度 年度销售表 [prev()]/@ 销售额 -@ 销售额 @ 销售额 @ 年度 比去年同期新增 ( 万元 ) 销售额 ( 万元 ) 年度
节点操作 ( 一 ) 绝对定位 包括树根的引用 , 如  //dataset/mydataset,  引用一个数据源 //system/pageno  引用页号系统变量 相对定位 如节点为 //dataset 的情况下 , mydataset  ,  等同于  //dataset/mydataset
节点操作 ( 二 ) 兄弟节点定位 (LAST,NEXT,PREV,FIRST) //dataset/mydataset[NEXT]  当前行 , 下一行数据 //dataset/mydataset[2]  第三行数据 //dataset/ 年度销售表 [PREV]/@ 销售额  取得上一年度销售额 祖先及子孙节点 //dataset/mydataset[PARENT]  选取父节点 //dataset/mydataset[..]  同上 //dataset/mydataset/@total[0]  第一行 ,total 列数据
节点操作 ( 三 ) 节点排序 ( 列节点 , 表节点 ) //dataset/mydataset.order(@id)  根据 id, 从小到大排序 //dataset/mydataset.order(@ 工资  +)  按工资从大到小排列   //dataset/mydataset.order(@ 工资  +,@ 年龄 )  按工资从大到小 , 年龄从小到大排列  节点分组统计 根据月份 , 姓名 , 合计工资 //dataset/mydataset.group(@ 月份  ,@ 姓名 ,sum(@ 工资 ) by  月份 , 姓名 )
节点操作 ( 四 ) 节点选择 选择同节点的列 , //dataset/mydataset.select(@id,@name,@ 工资 ) 选择下一节点的列 , 作为列 //dataset/mydataset.select(@id,@name,@ 工资 , 工资经历 [FIRST]/@ 单位 ) 列节点统计 (sum,min,max,avg,count) 合计工资 //dataset/mydataset/@ 工资 .sum ()
表格节点的管道操作 表格节点的操作 选择操作  select 过滤操作  […] 排序操作  order 分组统计操作  group 分段统计  select(*,seg(@key,[1,2,3,4],[1,2,3,4]) as xx )
列定义 ( 一 ) 列定义使用在 select 中 Dataset.select([*],[, 列定义 ]+) *, 表示选取所有列 列定义可以使用  [ 列表达式 ] [as [ 列名 ]]   列定义表达式 @ 单价  * @ 数量  as  金额 @ 单价  as  新单价 @ 单价
SEG,RANK 列函数 分段函数 Seg seg( 名次 <15 , 名次 >=15 &&  名次 <35,  名次 >=35],[“ 优” ,” 良” ,” 差” ]) as  级别 把 15 名以下的称为优 ,15-35 称为良 ,35 以上的称为差 排名函数 rank //  按分数降序排 selecta(rank( 分数  desc) as  名次 )  //  按 gdp 升序排 selecta(rank(GDP asc) as  名次 )
列函数综合举例 学生成绩表 学生名 , 班级 , 分数  ->  班级 级别  人数 x = 学生成绩表 .selecta(rank( 分数 ) as  名次 ); x= x.select( 班级 , seg(@ 名次 <15 ,@ 名次 >=15 && @ 名次 <35, @ 名次 >=35],[“ 优” ,” 良” ,” 差” ]) as  级别 ); x=x.group(*,count() as  人数  by  班级 , 级别 ); 5<aaa<10;
多阶段布局模型 组件类型 原始组件 集合组件 ( 表格 , 表格容器 , 页面 ), 组件大小 , 位置 对齐
多阶段布局模型 布局队段 , 输出 , 分页 页脚 , 页眉 ,
Crosstab  组件布局 行表 , 列表 , 交叉表 列表折页处理 当交叉报表宽度超过页宽时 , 自动将多余部分 , 在下页打印 是否显示列头 , 行头 , 还是全选 , 都可选
固定布局 行表 , 列表 , 交叉表 打印列表 , 打印行表 , 打印出列表 列表自动折页处理 c rosslayout( 列表 , 行表 , 交叉表 ) crosslayout( 列表 , 行表 .select(0..*,10..20), 交叉表 (0..*,10,20)]; table.add( 列表 ,0,0); table.add()
流式布局 行表 , 列表 , 交叉表 打印列表 , 打印行表 , 打印出列表 c rosslayout( 列表 , 行表 , 交叉表 ) crosslayout( 列表 , 行表 .select(0..*,10..20), 交叉表 (0..*,10,20)]; table.add( 列表 ,0,0); table.add()
杰表架构 XmlSerializer Export PageGen Components DataModel Scripts
DataModel DataSet SqlDataReader CsvDataReader DataReader
//  *  部门 --+ //  *  | //  *  人员表 : 姓名 年龄 部门 ------------+------------------------------------------ 部门  |  年龄段 +------------------------------------------ |   0-15 岁 ( 少年 )  15-30 岁 ( 青年 )  30-40 岁 ( 壮年 )  40 岁以 ( 暮年 ) ------------------------------------------------------- |  = 人员表 \{ 年龄 <15 &&  部门 ==$ 部门 }.COUNT  3  8  0 |  2  4  1  0 |  1  5  2  0 |  2  6  0  0 |  0  7  1  0 |  1  8  3  0 |  2  9  0  0 ------------+------------------------------------------- = 人员表 \ 年龄 { 年龄 <15}.COUNT Select *
主从报表数据模型 body Table ( 学生 ) header body List (// 班级 / 学生 )         @ 名次 @ 成绩 @ 学生名 @ 学号 名次 成绩 学生名 学号             @ 班长 班长     @ 班主任 班主任     @ 班级 班级号        
主从报表效果         1 600 小李 9905 2 500 小王 9902 3 400 小张 9901 名次 期中成绩 学生名 学号           张国荣 班长   王小曼 班主任     高三 1 班级号        
主从报表数据模型 人员表 .y 轴 人员表 .x 轴 人员表 1[@ 部门 =: 部门  &&  年龄段 =: 年龄段 ]       总计        body  41-55 31-40 20-30 年龄段 部门 18 22 17 总计  2 3 3 财务部    5 2 经理办公室    0 2 研发部  4 0 4 生产部  4 0 3 技术部  5 8 2 广告部  3 6 1 市场部  41-55 31-40 20-30 年龄段 部门

杰表.2008报表实例研究

  • 1.
    杰表 .2008 报表实例研究 杭州杰创软件拥有版权 .www.jatools.com
  • 2.
    现存问题 复杂交叉报表困难 不能同期比不能交互式排序 不能折列操作
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
    原因分析 模型缺陷 无状态-> 不能随时得到数据 , 数据模型生命周期 , 不清晰
  • 9.
    Model 的生命周期 Model分为无状态 , 有状态两种 无状态 服务器端不保存 , 适合数据量大 , 不需要动态互的报表 , 比如 , 资产负债表 有状态 服务器端缓存 , 适合数据量小 , 需要动态分析的报表 , 如 olap, 销售分析
  • 10.
    有状态数据模型生命周期 初始化 在启一个报表任务时, 由报表负责初始化 服务 向报表引擎提供服务 , 包括初始化 , 动态交互 , 数据模型可能为多个报表任务提供服务 销毁 当 session 结束时 , 自动从内存中销毁
  • 11.
    无状态数据模型生命周期 初始化 在启一个报表任务时, 由报表负责初始化 服务 为一个报表任务提供服务 销毁 在一个报表任务结束时销毁
  • 12.
    Model 语言 原数据类型所有可用的 java 类型 , 包括 Integer,String,Double,Float,BigDecimal 等
  • 13.
    Model 语言 节点类型 单元 , 行 , 列 , 表格 表格 单元 // 数据源 / 班级 /@ 班长 列 // 数据源 / 班级 [0] 行
  • 14.
    单元节点引用 行节点 \@列名 dataset\ 年度销售表 [0]\@ 销售额 表 \@ 列 [i] dataset\ 年度销售表 \@ 销售额 [0] @ 列 @ 销售额
  • 15.
    单元节点运算 取决于值类型的运算 单元节点 , 根据其数值类型 , 可以使用相应运算 , 比如代数运算 , 及方法 如 String 类型 \\ 系统变量 \$$user.indexOf(“admin”); 如 int 类型 \\ 数据源 \ 学生 [0]\@ 年龄 +100
  • 16.
    行节点运算 \, 取列值 班级表 [0]\@ 班长 // ” 班长”列值
  • 17.
    列节点运算 ( 一) sum,min,max,avg,count 班级表 \ 学生表 \@ 分数 .avg() // 求平均分数 班级表 \ 学生表 \@ 分数 .max() // 求最高分 group( 按升序分组 ),group_desc( 按降序分组 ) 销售表 \@ 客户 .group() // 取客户列表 , 注 : group() 所得结果 , 也是列节点类型 , 因此可用列节点的运算 , 比如 , 销售表 \@ 客户 .group().count(), // 取客户数 order( 按升序排序 ), order_desc( 按降序 ) 班级表 \ 学生表 \@ 分数 .order_desc() // 按分数从高到底排序 注 : order() 所得结果 , 也是列节点类型 rank( 按升序排名 , 数值大的 , 名次在后 ),rank_desc( 数值大 , 名次靠前 ) 班级表 \ 学生表 \@ 分数 .rank_desc() // 按分数越高 , 名次越前
  • 18.
    列节点运算 ( 二) [i] 求某一位置单元值 , 班级表 \ 学生表 \@ 分数 [2] // 第三位置的分数 last() ,first() 求首尾的值 班级表 \ 学生表 \@ 分数 .last() // 最后一个分数 seg(c1,c2,c3,... as v1,v2,v3...), 分段函数 @ 分数 ={50,55,80,90,99,30,70,65} // 60 分以下为差 ,85 以下 , 为良 ,85 分以上为优 x = 班级表 \ 学生表 \@ 分数 .seg(<60,<85,>85 to “ 及格” ,” 良” ,” 优” ) ; // 经过上述运算后 , 所得结果为 // x ={“ 差” ,” 差” ,” 良” ,” 优” ,” 优” ,” 差” ,” 良” ,” 良” } 注 : seg() 所得结果 , 也是列节点类型
  • 19.
    表节点运算 ( 一) 取某一行 ,[i], last() ,first() 班级表 \ 学生表 [2] // 第三行 班级表 \ 学生表 .last() // 取最后一行 选择 ,select 学生表 .select(@ 学生名 ,@ 年龄 as age, @ 助学金 * 0.09 as bonus); // 返回表节点 过滤 ,[] 学生表 [@ 学生名 .startWith(“ 王” )] // 取得所有姓”王”的记录 , 返回类型 , 表节点 增加列 ,addcol 学生表 .addcol(@ 分数 .rank_desc() as 排名 ); // 增加分数排名列 销售表 .addcol(@ 单价 * @ 数量 as 金额 ) // 增加金额列
  • 20.
    表节点运算 ( 二) rows/count,columns, 取行数 , 列数 班级表 .rows() // 取行数 , 也可使用 count() 方法 班级表 .columns() // 取列数 /, 取子节点 销售额 /@ 销售额 // 取销售额 班级表 / 学生表 // 取学生表子节点 cross_select(), 取得交叉数据表 学生表 .cross_select([@ 年度 ,@ 季度 ],[@ 地区 ],[@ 销售额 .sum()]); // 返回交叉表
  • 21.
    交叉表运算 交叉表由 cross_select方法得到 x=cross_select([@ 年度 ,@ 季度 ],[@ 地区 ],[@ 销售额 .sum()]); // 返回交叉表 取得轴表 ,axis0,axis1 x.axis0() // 得到第一轴表 x.axis1() // 取第二轴表 measure(), 取得度量表 x.measure()\@ 总销售 ; // 取得总销售
  • 22.
    同期比示例 -50 12502004 100 1300 2003 200 1200 2002 - 1000 2001 比去年同期新增 ( 万元 ) 销售额 ( 万元 ) 年度 年度销售表 [prev()]/@ 销售额 -@ 销售额 @ 销售额 @ 年度 比去年同期新增 ( 万元 ) 销售额 ( 万元 ) 年度
  • 23.
    节点操作 ( 一) 绝对定位 包括树根的引用 , 如 //dataset/mydataset, 引用一个数据源 //system/pageno 引用页号系统变量 相对定位 如节点为 //dataset 的情况下 , mydataset , 等同于 //dataset/mydataset
  • 24.
    节点操作 ( 二) 兄弟节点定位 (LAST,NEXT,PREV,FIRST) //dataset/mydataset[NEXT] 当前行 , 下一行数据 //dataset/mydataset[2] 第三行数据 //dataset/ 年度销售表 [PREV]/@ 销售额 取得上一年度销售额 祖先及子孙节点 //dataset/mydataset[PARENT] 选取父节点 //dataset/mydataset[..] 同上 //dataset/mydataset/@total[0] 第一行 ,total 列数据
  • 25.
    节点操作 ( 三) 节点排序 ( 列节点 , 表节点 ) //dataset/mydataset.order(@id) 根据 id, 从小到大排序 //dataset/mydataset.order(@ 工资 +) 按工资从大到小排列 //dataset/mydataset.order(@ 工资 +,@ 年龄 ) 按工资从大到小 , 年龄从小到大排列 节点分组统计 根据月份 , 姓名 , 合计工资 //dataset/mydataset.group(@ 月份 ,@ 姓名 ,sum(@ 工资 ) by 月份 , 姓名 )
  • 26.
    节点操作 ( 四) 节点选择 选择同节点的列 , //dataset/mydataset.select(@id,@name,@ 工资 ) 选择下一节点的列 , 作为列 //dataset/mydataset.select(@id,@name,@ 工资 , 工资经历 [FIRST]/@ 单位 ) 列节点统计 (sum,min,max,avg,count) 合计工资 //dataset/mydataset/@ 工资 .sum ()
  • 27.
    表格节点的管道操作 表格节点的操作 选择操作 select 过滤操作 […] 排序操作 order 分组统计操作 group 分段统计 select(*,seg(@key,[1,2,3,4],[1,2,3,4]) as xx )
  • 28.
    列定义 ( 一) 列定义使用在 select 中 Dataset.select([*],[, 列定义 ]+) *, 表示选取所有列 列定义可以使用 [ 列表达式 ] [as [ 列名 ]] 列定义表达式 @ 单价 * @ 数量 as 金额 @ 单价 as 新单价 @ 单价
  • 29.
    SEG,RANK 列函数 分段函数Seg seg( 名次 <15 , 名次 >=15 && 名次 <35, 名次 >=35],[“ 优” ,” 良” ,” 差” ]) as 级别 把 15 名以下的称为优 ,15-35 称为良 ,35 以上的称为差 排名函数 rank // 按分数降序排 selecta(rank( 分数 desc) as 名次 ) // 按 gdp 升序排 selecta(rank(GDP asc) as 名次 )
  • 30.
    列函数综合举例 学生成绩表 学生名, 班级 , 分数 -> 班级 级别 人数 x = 学生成绩表 .selecta(rank( 分数 ) as 名次 ); x= x.select( 班级 , seg(@ 名次 <15 ,@ 名次 >=15 && @ 名次 <35, @ 名次 >=35],[“ 优” ,” 良” ,” 差” ]) as 级别 ); x=x.group(*,count() as 人数 by 班级 , 级别 ); 5<aaa<10;
  • 31.
    多阶段布局模型 组件类型 原始组件集合组件 ( 表格 , 表格容器 , 页面 ), 组件大小 , 位置 对齐
  • 32.
    多阶段布局模型 布局队段 ,输出 , 分页 页脚 , 页眉 ,
  • 33.
    Crosstab 组件布局行表 , 列表 , 交叉表 列表折页处理 当交叉报表宽度超过页宽时 , 自动将多余部分 , 在下页打印 是否显示列头 , 行头 , 还是全选 , 都可选
  • 34.
    固定布局 行表 ,列表 , 交叉表 打印列表 , 打印行表 , 打印出列表 列表自动折页处理 c rosslayout( 列表 , 行表 , 交叉表 ) crosslayout( 列表 , 行表 .select(0..*,10..20), 交叉表 (0..*,10,20)]; table.add( 列表 ,0,0); table.add()
  • 35.
    流式布局 行表 ,列表 , 交叉表 打印列表 , 打印行表 , 打印出列表 c rosslayout( 列表 , 行表 , 交叉表 ) crosslayout( 列表 , 行表 .select(0..*,10..20), 交叉表 (0..*,10,20)]; table.add( 列表 ,0,0); table.add()
  • 36.
    杰表架构 XmlSerializer ExportPageGen Components DataModel Scripts
  • 37.
    DataModel DataSet SqlDataReaderCsvDataReader DataReader
  • 38.
    // * 部门 --+ // * | // * 人员表 : 姓名 年龄 部门 ------------+------------------------------------------ 部门 | 年龄段 +------------------------------------------ | 0-15 岁 ( 少年 ) 15-30 岁 ( 青年 ) 30-40 岁 ( 壮年 ) 40 岁以 ( 暮年 ) ------------------------------------------------------- | = 人员表 \{ 年龄 <15 && 部门 ==$ 部门 }.COUNT 3 8 0 | 2 4 1 0 | 1 5 2 0 | 2 6 0 0 | 0 7 1 0 | 1 8 3 0 | 2 9 0 0 ------------+------------------------------------------- = 人员表 \ 年龄 { 年龄 <15}.COUNT Select *
  • 39.
    主从报表数据模型 body Table( 学生 ) header body List (// 班级 / 学生 )         @ 名次 @ 成绩 @ 学生名 @ 学号 名次 成绩 学生名 学号             @ 班长 班长     @ 班主任 班主任     @ 班级 班级号        
  • 40.
    主从报表效果        1 600 小李 9905 2 500 小王 9902 3 400 小张 9901 名次 期中成绩 学生名 学号           张国荣 班长   王小曼 班主任     高三 1 班级号        
  • 41.
    主从报表数据模型 人员表 .y轴 人员表 .x 轴 人员表 1[@ 部门 =: 部门 && 年龄段 =: 年龄段 ]       总计       body 41-55 31-40 20-30 年龄段 部门 18 22 17 总计 2 3 3 财务部   5 2 经理办公室   0 2 研发部 4 0 4 生产部 4 0 3 技术部 5 8 2 广告部 3 6 1 市场部 41-55 31-40 20-30 年龄段 部门