18 · 分组行与小计输出
场景
你的发票 / 结算单 / 采购订单工作簿里有明细行,按客户或月份切成多个段落,每段后面跟一行小计,(可选)最底部还有一行总计:
北京物流 部件 A 10,000
北京物流 部件 B 5,000
小计 15,000
上海贝塔工程 部件 A 20,000
小计 20,000
总计 35,000
XTL 0.6 提供了两个指令,可以在同一个数据块内完成这件事,不需要在源里预聚合,也不需要在输出后再后处理(ADR-0038)。
两个组件
@group [Key1], [Key2], …
@group 把活动行集合分成 N 层嵌套分组,用于交错输出小计。它不重新排序——分组顺序是 @filter 与 @sort 应用之后的出现顺序。要稳定分组顺序,请配合用相同键的 @sort。
{{ @sort [客户] }}
{{ @group [客户] }}
@subtotal <aggregate>
包含 {{ @subtotal SUM([金额]) }} 单元格的行就是一条小计行。它不会按每条源行迭代;而是在每个分组边界、按该行绑定的层级,由渲染器在合适的时机输出一次。支持的聚合:SUM、COUNT、AVERAGE、MIN、MAX。
源顺序中的第一条 @subtotal 行绑定到最内层分组键。在它下方堆叠更多 @subtotal 行可绑定到外层——最底下的那行绑定到最外层键。
单层分组
{{ @sort [客户] }}
{{ @group [客户] }}
{{ [客户] }} | {{ [品项] }} | {{ [金额] }}
"小计" | | {{ @subtotal SUM([金额]) }}
对 3 条源(北京物流/部件/100、上海贝塔工程/螺栓/50、北京物流/齿轮/200)的渲染结果:
北京物流 部件 100
北京物流 齿轮 200
小计 300
上海贝塔工程 螺栓 50
小计 50
二层嵌套 + 总计
{{ @sort [区域] }}
{{ @sort [客户] }}
{{ @group [区域], [客户] }}
{{ [区域] }} | {{ [客户] }} | {{ [金额] }}
"客户小计" | | {{ @subtotal SUM([金额]) }}
"区域小计" | | {{ @subtotal SUM([金额]) }}
最靠上的 @subtotal 行(客户小计)绑定到最内层键 [客户];下一行(区域小计)绑定到 [区域]。两者都在各自的边界输出;当两个边界同时结束时,内层先 fire。
"用最外层 @subtotal 实现总计"模式:在单个 @group [客户] 配上两条 @subtotal 行时,外层那条恰好在数据块末尾 fire 一次——因为最外层分组的边界就是数据的末尾。
与其他指令的组合
| 指令 | 交互 |
|---|---|
@filter | 过滤在分组之前应用。被过滤掉的行不属于任何分组。所有行都被过滤掉的分组直接不出现。 |
@sort | 排序在分组之前应用。 要固定分组顺序,请按与 @group 相同的键、相同的顺序 @sort。 |
@source | 每个 @source 块都有自己的分组作用域。 |
@join | 连接行的列像主表行的列一样参与分组。分组键可以引用被连接源的列。 |
@top | 在分组之后按行级应用。只有经过 @top 裁剪后仍有数据行的分组,其小计才会被输出。 |
@repeat right | 与 @group 不兼容(xl3/directive/invalid-syntax)。 |
边界情况
- 单一分组退化情形 ——
@group [Key]且所有行都共享同一个[Key]值时,小计仍会在该分组边界输出一次。当数据集刚好只含一个外层分组值时,这与总计模式一致。 - 空分组 ——所有数据行都为空(按 ADR-0007)的分组会被跳过:既不输出数据行,也不输出
@subtotal。 - 聚合参数 ——
@subtotal内只接受列引用。复合表达式(SUM([A]) - SUM([B])、IF(...))会抛出xl3/subtotal/bad-aggregate,并被延后。 @subtotal行上的字面文本单元格 ——可以;"小计:"这种标签可以跟聚合单元格并排,并在每次输出时一起渲染。字面单元格不可引用当前行列;分组边界处没有"当前行"。
错误码
xl3/group/missing-key——@group指令缺少键列表。xl3/subtotal/outside-group——不带@group的块里出现了@subtotal单元格,或@subtotal行数多于@group键数。xl3/subtotal/bad-aggregate——主体不是SUM、COUNT、AVERAGE、MIN、MAX之一,或其参数不是列引用。
另见
- ADR-0038 —
@group与@subtotal指令 spec/language.md§ "Group + Subtotal"- Cookbook 03 — 聚合 ——不分组的块级
SUM/COUNT/AVERAGE - Cookbook 15 — 指令组合 ——完整的指令顺序规则