订阅更新

多币种数仓怎么建模?汇率变化会不会改掉历史金额?

面试问 264 约 3 分钟读完

本文目录
  1. 面试怎么回答
  2. 原币事实不能被换算结果覆盖
  3. 汇率不是只有日期和值
  4. 冻结口径与重述口径应分开
  5. 一个典型场景:原币没有变化,历史金额天天变
  6. 缺失汇率,不能兜底为一
  7. 精度与对账要保留分层结果
  8. 参考资料

面试怎么回答

我会同时保存原币金额、币种、统一币金额,以及所用汇率的币对方向、生效日期、类型和版本。历史交易按哪天汇率换算要由已确认的业务规则决定,不默认用最新值。冻结口径应可复现,按新汇率重述则另设指标。还要校验汇率缺失、一对多关联和精度,不能把缺失汇率兜底为一,也不能把不同币种原币金额直接相加。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

历史订单用交易时汇率换算,还是每次查询都乘最新汇率?前者方便复盘,后者可能满足重述分析。两种需求都有人要,但如果共用一个没有版本说明的“人民币金额”,历史报表就很难解释。

原币金额、统一币金额和汇率依据要共同保留;历史冻结与按新汇率重述,是两种不同指标。

原币事实不能被换算结果覆盖

多币种事实表至少保留原币金额和币种。若源系统使用分、厘或其他最小单位,还要明确单位与缩放规则;只保存一个 amount,不知道它是美元还是日元,后续换算没有可靠起点。

统一报告币金额是派生结果,应与原值共存,而不是覆盖原值。否则汇率选择错了、币对方向反了,修复时连重新计算的依据都没有。Kimball 的多币种建模也强调同时保留交易币与标准币的事实表达。

本篇讨论数据建模,不决定会计确认、汇兑损益或财务报表规则;这些应使用组织已确认的制度,不能由技术人员随意选一天汇率代替。

汇率不是只有日期和值

一条汇率通常需要说明原币、目标币、生效日期或时间、汇率类型、来源和版本。现汇买入、中间价、业务约定价等标签,表达的是不同规则,不应混用成同一个“当天汇率”。

还必须确定方向。若 rate 定义为“一单位原币可兑换多少目标币”,统一币金额才是原币金额乘 rate;反向报价需要按已确认规则转换。币对方向弄反,SQL 仍能正常执行。

同一日期可能有多个来源、多个修订版本,因此关联键要包含足够条件,并在规则范围内唯一。只用日期和币种 Join,很容易让一笔订单关联到多条汇率,金额被放大。

冻结口径与重述口径应分开

假设某笔 100 USD 的交易,使用的示意汇率是每美元 7 元,冻结换算值为 700 元;后来分析按另一版示意汇率 7.2 重述,结果为 720 元。这里的汇率仅用于演示,不是实际行情。

冻结口径回答“按当时采用的规则是多少”,重述口径回答“按指定新规则重新看是多少”。两者都应保留名称、版本与使用条件,不能今天更新汇率表,昨天的同名指标就悄悄变成另一种含义。

关键关系图

可以在事实中保留实际使用的 rate_id、rate_value 和转换结果,也可以通过不可变版本的汇率表复现。关键不是一定存在哪一列,而是查询所依赖的版本不能无声改变。

一个典型场景:原币没有变化,历史金额天天变

比如历史经营看板每天查出来都略有不同,源订单没有更新,最初怀疑金额字段的精度处理不稳定。沿着 SQL 查看,发现查询始终选择汇率表里的最新版本。

根因是动态关联让历史金额被反复重估。旧检查只比较原币行数和总额,当然看不出问题;测试也没有覆盖汇率更新后的重复查询。修复应区分冻结与重述指标,并给固定输入、固定版本建立可复现性检查。

如果组织确实允许历史重算,应该将其做成有记录的版本发布,明确影响范围,而不是让一个基础维表更新意外触发所有历史报告变化。

缺失汇率,不能兜底为一

原币与目标币确实相同,汇率为一才有明确意义。其他币对缺失时直接 COALESCE(rate, 1),会把未换算金额伪装成已换算金额,之后所有汇总都失去币种含义。

应该区分同币种、正常匹配、缺失和多重匹配,并为异常记录设置隔离或阻断规则。允许使用上一有效汇率时,也要明确最长沿用范围和来源日期,不能无限向前填。

精度与对账要保留分层结果

金额与汇率通常使用明确精度的定点数,并分别定义计算精度和展示精度。先逐笔舍入再汇总,与先高精度汇总再舍入,可能出现尾差,必须按既定口径验证。

对账可以先按原币币种核对原始金额,再检查匹配汇率的覆盖率和唯一性,最后比较统一币结果。不同币种的原币金额不能直接相加后再乘一个平均汇率。

退款、冲正和补录也应沿用明确的转换规则,不默认沿用原订单汇率或直接使用当前汇率。只要把日期、类型和版本写进契约,跨系统差异才有可追溯的解释路径。

参考资料

刷题进度保存在当前浏览器