使用SQL与BIRT实现带子表的横向多联系人报表开发咨询
实现方案
这个需求的核心是同一Cert下多行Contact数据的行转列(透视)操作,结合你手头的SQL+BIRT工具栈,有两个可直接落地的路径,按需选就行。
方案1:SQL层完成数据透视,BIRT直接做普通报表
这个方案调试成本最低,BIRT侧不需要做复杂配置,拿到结果集直接绑字段就能出表,优先推荐。
核心逻辑是先给每个Cert分组下的Contact编排序号,再按序号把值映射到对应列:
- 先给联系人表的记录加组内序号,按Cert分组,给组内每条Contact按你需要的规则排1、2、3…的顺位。支持窗口函数的数据库(MySQL8.x+、PostgreSQL、SQL Server、Oracle等)直接用窗口函数实现:
SELECT Cert, Contact, ROW_NUMBER() OVER (PARTITION BY Cert ORDER BY Contact) AS contact_seq FROM 联系人表
如果是不支持窗口函数的老版本数据库,用自定义变量、关联子查询的方式也能实现组内编号,逻辑一致。
- 关联Cert-Type主表,用条件聚合做行转列,直接输出最终报表需要的表结构:
SELECT t1.Cert, t1.Type, MAX(CASE WHEN t2.contact_seq = 1 THEN t2.Contact END) AS Contact1, MAX(CASE WHEN t2.contact_seq = 2 THEN t2.Contact END) AS Contact2, MAX(CASE WHEN t2.contact_seq = 3 THEN t2.Contact END) AS Contact3 FROM Cert类型表 t1 LEFT JOIN ( -- 上面第一步生成带序号的联系人子查询 SELECT Cert, Contact, ROW_NUMBER() OVER (PARTITION BY Cert ORDER BY Contact) AS contact_seq FROM 联系人表 ) t2 ON t1.Cert = t2.Cert GROUP BY t1.Cert, t1.Type -- 如果需要和示例一样只保留恰好3个联系人的Cert,就放开下面这行 -- HAVING COUNT(t2.Contact) = 3
跑出来的结果和你要的报表结构完全一致,BIRT里新建普通表格,把对应字段拖到单元格里就能用。如果后续需要支持更多联系人,照着现有Contact列的写法加Contact4、Contact5的判断就行。
方案2:SQL只做基础关联,透视逻辑放BIRT侧实现
如果你不想把转换逻辑写在SQL里,也可以直接在BIRT报表层处理:
- 先写最简单的两表关联SQL,输出长表格式的结果,按Cert排序:
SELECT t1.Cert, t1.Type, t2.Contact FROM Cert类型表 t1 LEFT JOIN 联系人表 t2 ON t1.Cert = t2.Cert ORDER BY t1.Cert
- BIRT里新建报表,对结果集按Cert字段建分组:
- 分组表头行放置Cert、Type字段
- 明细行不要直接平铺Contact字段,利用BIRT的组内行号函数做判断:组内第1行的Contact值渲染到Contact1单元格,第2行渲染到Contact2,第3行渲染到Contact3,超出3个的联系人直接设置隐藏规则即可
- 最后把明细行的高度合并,让同一组的多个联系人值显示在同一行的对应列里
这个方案的优势是后续联系人列数变动时不需要修改SQL,只要调整报表模板配置就行,缺点是模板配置比方案1稍繁琐。
注意事项
- Contact的排序规则如果不是按姓名字典序,把上述代码里
ORDER BY Contact换成你实际需要的排序字段(比如联系人创建时间、对接优先级),不然每次生成报表时Contact1/2/3的对应人员可能不固定。 - 如果业务上需要保留联系人不足3个的Cert,不需要额外处理,对应Contact列会自动留空。
内容的提问来源于stack exchange,提问作者Brian
相关产品推荐
相关产品推荐

