使用ssrs矩阵
要把原代码的 Excel 导出功能转成 SSRS 报表,报表设计是最核心的环节 —— 尤其是如何用 “数据集” 准备数据,用 “矩阵” 处理动态列(比如不确定数量的维度),这部分很容易 confusion,下面用 “大白话 + 实例” 讲透。
先明确一个核心目标
报表最终要长成这样(和原 Excel 一致):
plaintext
┌───────────┬───────────┬───────────┬───────────┬───────────┬...(其他余额列)
│ 维度1名称 │ 维度2名称 │ 科目描述 │ 交易币种 │ 期初本位币 │
├───────────┼───────────┼───────────┼───────────┼───────────┼
│ 维度1值 │ 维度2值 │ 银行存款 │ CNY │ 1000.00 │
│ 维度1值 │ 维度2值 │ 应收账款 │ USD │ 2000.00 │
└───────────┴───────────┴───────────┴───────────┴───────────┘
其中,“维度 1、维度 2” 的数量不固定(可能 1 个,也可能 5 个,取决于系统配置的财务维度集),这就是 “动态列”;“科目描述、币种、余额” 是固定不变的列。
一、数据集:报表的数据 “粮仓”
数据集(Dataset)就是报表的 “数据源”,相当于提前把要显示的数据整理成一张 “表格”,报表里的文字、数字都从这张 “表格” 里取。
原代码里的数据存在临时表ledgerTrialBalanceTmp中,SSRS 报表也需要基于这张表做数据集,但要拆成两个:一个存实际业务数据,一个存动态维度的名称。
1. 主数据集(MainDataset):存业务数据
作用:存储所有要显示的行数据(比如每一行的维度值、科目描述、各种余额)。
怎么来的?对应原代码的generateData方法 —— 通过LedgerTrialBalanceTmp::calculateBalances_V2生成的ledgerTrialBalanceTmp临时表。我们只需要把这张表的字段 “挑出来” 做成数据集。
具体字段(必须包含这些):
| 字段类别 | 例子(对应原代码) | 说明 |
|---|---|---|
| 动态维度值 | DimensionValues1、DimensionValues2... | 第 1 个维度的值、第 2 个维度的值(最多 N 个) |
| 固定基础信息 | PrimaryFocusDescription(科目描述) | 原代码里的科目文本 |
| 固定基础信息 | YMZTransactionCurrency(交易币种) | 原代码里的币种字段 |
| 余额数据 | YMZOpeningBalanceBaseCurrency(期初本位币) | 原代码里的余额字段 |
| 其他余额数据 | 借方 / 贷方 / 期末的本位币、交易币字段 | 同上,按原代码字段一一对应 |
配置方法:在 D365 的报表设计工具(如 Visual Studio 的 Report Designer)中,新建一个数据集,数据源选 “查询”,然后选我们提前建好的YMZLedgerTrialBalanceQuery(这个查询关联了ledgerTrialBalanceTmp临时表,并包含上述所有字段)。
2. 维度信息数据集(DimSegmentsDataset):存动态维度的名称
作用:告诉报表 “有多少个维度”“每个维度叫什么名字”(比如 “部门”“成本中心”),用于动态生成表头。
怎么来的?对应原代码的dimensionSetSegmentNames—— 从DimensionHierarchyLevel::getDimensionHierarchyLevelNames获取的维度名称。我们需要把这些名称和对应的序号(第 1 个、第 2 个)做成数据集。
具体字段:
| 字段名 | 说明 |
|---|---|
SegmentNumber | 维度序号(1、2、3...) |
SegmentName | 维度名称(如 “部门”“成本中心”) |
配置方法:新建一个数据集,数据源可以是自定义的方法(X++),比如写一个方法getDimensionSegments(),返回包含上述字段的临时表(里面存着当前配置的维度序号和名称)。
二、矩阵(Matrix):处理动态列的 “神器”
报表里的 “动态维度列”(数量不固定)必须用矩阵组件来做。矩阵和 Excel 的 “数据透视表” 很像,能根据数据自动生成列(或行)。
如果用普通的 “表格” 组件,列数是固定的,没法应对 “有时 3 个维度,有时 5 个维度” 的情况;而矩阵的 “列组” 可以动态生成列,完美解决这个问题。
矩阵的核心结构(先看懂这个再动手)
矩阵有 3 个核心区域,对应到我们的报表需求:
plaintext
┌───────────────────────────────────── 列组(动态维度列) ─────────────────────────────────────┐
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ 维度1名称 │ │ 维度2名称 │ │ 维度3名称 │ ...(固定列:科目描述、币种、余额...) │
│ └───────────┘ └───────────┘ └───────────┘ │
├────────────────────────────────── 数据区域(维度值) ──────────────────────────────────────┤
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ 维度1值 │ │ 维度2值 │ │ 维度3值 │ ...(固定列的值) │
│ └───────────┘ └───────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────────────┘
行组(这里不需要额外分组,默认一行一条数据)
- 列组(Column Group):控制 “动态维度列” 的表头(显示维度名称),由
DimSegmentsDataset的SegmentNumber和SegmentName驱动。 - 数据区域(Data):填充动态维度列的值(比如 “维度 1 值”“维度 2 值”),从
MainDataset的DimensionValues1等字段取。 - 行组(Row Group):这里不需要分组(因为每一行就是一条独立的数据),保持默认即可。
手把手配置矩阵(以 “3 个维度” 为例)
假设系统当前配置了 3 个维度(部门、成本中心、项目),我们一步步让矩阵显示这 3 列。
步骤 1:添加矩阵到报表
在 Report Designer 的 “工具箱” 里拖一个 “Matrix” 到报表主体(Body)中,会看到默认的矩阵结构:
plaintext
┌────────────┬────────────┐
│ [列组] │ [数据] │
├────────────┼────────────┤
│ [行组] │ [数据] │
└────────────┴────────────┘
步骤 2:配置列组(动态显示维度名称)
目标:让列组根据DimSegmentsDataset的SegmentNumber生成 3 列,每列的表头显示SegmentName(如 “部门”“成本中心”)。
- 右键矩阵的 “列组” 区域(默认显示 “[列组]” 的地方),选 “添加组”→“父组”。
- 在弹出的窗口中,“分组依据” 选
DimSegmentsDataset的SegmentNumber(维度序号)。 - 勾选 “添加组头”,点确定。此时列组会生成一个基于
SegmentNumber的分组。 - 把列组表头的文本框(默认显示
[SegmentNumber])改成[SegmentName](从DimSegmentsDataset拖SegmentName字段到这里)。
此时列组会自动根据DimSegmentsDataset的数据生成列:如果有 3 个维度,就显示 3 列,表头分别是 “部门”“成本中心”“项目”。
步骤 3:配置数据区域(填充维度值)
目标:让动态列的单元格显示对应维度的值(如 “部门” 列显示DimensionValues1,“成本中心” 列显示DimensionValues2)。
- 矩阵中间的 “数据” 区域(默认显示
[数据]的地方)需要根据 “当前维度序号” 动态取MainDataset的DimensionValuesN字段。 - 这里需要用 “表达式” 判断:如果
SegmentNumber=1,就取DimensionValues1;SegmentNumber=2,就取DimensionValues2... - 右键数据区域的文本框,选 “表达式”,输入:
vb
这个表达式的意思是:根据当前列的维度序号(1/2/3),显示对应的维度值字段。=Switch(Fields!SegmentNumber.Value = 1, Fields!DimensionValues1.Value,Fields!SegmentNumber.Value = 2, Fields!DimensionValues2.Value,Fields!SegmentNumber.Value = 3, Fields!DimensionValues3.Value-- 按系统最大维度数补充,比如最多10个就写到10 )
步骤 4:添加固定列(科目描述、币种、余额等)
动态维度列配置完后,右侧需要添加固定列(和原 Excel 的固定列一致)。
- 右键矩阵的最右侧列,选 “插入列”→“在右侧”,插入新列(需要多少固定列就插多少)。
- 第一列固定列的表头:拖
@SYS92116(原代码中的科目描述标签)到表头文本框。 - 该列的数据区域:拖
MainDataset的PrimaryFocusDescription字段(科目描述的值)。 - 第二列固定列的表头:拖
@SYS62786(原代码中的币种标签)到表头。 - 该列的数据区域:拖
MainDataset的YMZTransactionCurrency字段(币种值)。 - 后续余额列(期初、借方、贷方等)以此类推:表头用原代码中的标签(如
@YMZ:OpeningBalanceBaseCurrency),数据区域拖对应的余额字段(如YMZOpeningBalanceBaseCurrency)。
步骤 5:设置数字格式(余额字段必做)
原代码中余额字段是 “0.00” 格式,报表里也要保持一致:
- 右键余额字段的数据文本框(如
[YMZOpeningBalanceBaseCurrency]),选 “文本框属性”。 - 切换到 “数字” 选项卡,选 “标准”,小数位数设为 “2”,点确定。
三、最终效果验证
配置完后,预览报表会看到:
- 动态维度列:根据系统配置的维度数量自动生成(比如 3 个维度就显示 3 列,表头是维度名称)。
- 动态列数据:每列显示对应维度的值(部门列显示部门值,成本中心列显示成本中心值)。
- 固定列:科目描述、币种、余额等字段按原格式显示,余额带 2 位小数。
和原 Excel 导出的效果完全一致,但更灵活(支持导出 PDF、打印等)。
关键总结
- 数据集是 “粮仓”:主数据集存业务数据(维度值、余额等),维度数据集存动态列的名称和序号。
- 矩阵是 “动态列工具”:用列组(基于维度序号)生成动态列,用表达式根据序号匹配维度值。
- 固定列直接加:动态列右侧插固定列,绑定对应字段即可。
