核心概念
Grain(粒度)
Grain 是对“一行究竟代表什么”的明确声明。它决定一行的 identity、金额字段能否直接计算,以及这张表可以或不能回答哪些问题。
同一份贷款合同可以拆出借据和还款记录;先说清一行代表什么,金额才有正确的落点。
Grain 是对“一行究竟代表什么”的明确声明。它决定一行的 identity、金额字段能否直接计算,以及这张表可以或不能回答哪些问题。
合同 C001 的约定金额是 100 万,但合同下可以有多笔实际放款。下面这个最小例子里,C001 对应借据 N001(30 万)和 N002(20 万);N001 又发生了 R001(5 万)和 R002(3 万),N002 发生了 R003(2 万)。
这些记录都属于同一条贷款链,却分别描述合同、实际放款和实际还款。把它们放进同一张表并不等于它们拥有同一个 Grain。
选择合同、借据或还款 Grain,查看当前一行、identity / 主键、行数、匹配金额,以及它能否回答某个问题。
如果把合同 C001 的 100 万 Join 到 N001 和 N002,再直接 SUM(contract_amount),一份合同就被算了两次。问题不在 SUM 函数,而在合同金额被带到了借据 Grain。
看到 Join 结果后,要先问“当前一行是什么”,再决定金额是否可以在这里计算。需要合同金额时,先回到 contract_id 唯一的合同 Grain,或明确只保留一次。
合同 C001 约定 100 万,下面的三张表记录的是三类不同事件。
这一行对应合同下的一笔实际放款,金额与实际形成的贷款本金对齐。
note_id / note_iddisbursed_principal · 实际放款本金示例数据中的记录数
note_id | contract_id | disbursed_principal |
|---|---|---|
| N001 | C001 | 300,000 |
| N002 | C001 | 200,000 |
合同金额被带到了两笔借据上
contract_amountcontract_id | note_id | contract_amount |
|---|---|---|
| C001 | N001 | 1,000,000 |
| C001 | N002 | 1,000,000 |
SUM(contract_amount)先观察 Join 结果,再执行聚合。