首页/数据/数仓建模速查/负向事实与冲正
维度与事实设计149 条

负向事实与冲正

退款或更正不删除原行,而是插入负向度量行,流水保持可审计,日终汇总时正负自然抵消。

数仓建模速查数据更新于 2026-10-13

负向事实与冲正是什么

负向事实与冲正指退款、撤销、更正发生时,不修改也不删除原记录,而是插入一条度量取负的新行,并通过原交易号引用被冲正的那笔。流水保持只插不改,任何时点回看都能完整审计;日终或任意区间汇总时,正负行自然抵消得到净额。直接改原行金额会破坏审计链,也无法回答「这笔钱什么时候退的」。

基本信息

基本原则只插不改,原行永久保留
冲正方式插入负向度量行,并引用原交易号
净额算法同一业务键 sum(amt),正负自相抵
必备字段原单引用、冲正类型、冲正发生时间
区分要求冲正行与原交易行的业务时间要分开记录

典型使用场景

  • 退款:退款成功时插入负金额支付行,与原支付抵消
  • 订单撤销:整单作废插入整单负向行,保留原因
  • 折扣更正:优惠算错时用负向行冲平,再补一条正确金额
  • 重复扣款修复:对多扣的那笔插一条等额负行
  • 跨月冲正:上月的错误在本月冲正,两个月的报表各自可解释
  • 账户调账:余额差异用负向事实记录,避免直接改期初

净额汇总与冲正

净额汇总与冲正
-- 净额:正负抵消,任意区间都成立
SELECT order_id, sum(pay_amt) AS net_amt
FROM   fact_payment
GROUP  BY order_id;

-- 冲正行插入:金额取负,原单引用必填
INSERT INTO fact_payment
       (pay_id, order_id, biz_date, pay_amt, pay_type, ref_pay_id)
VALUES ('R20261013001', 'O20261001001', '2026-10-13',
        -199.00, 'refund', 'P20261001001');

-- 冲正量监控:单日冲正金额占比异常升高要人工介入
SELECT biz_date,
       sum(case when pay_amt < 0 then -pay_amt else 0 end) AS refund_amt,
       sum(pay_amt) AS net_amt
FROM   fact_payment
GROUP  BY biz_date;

冲正与直接更新对照

维度插入负向行直接更新原行
可审计性完整保留正负流水原值丢失,无法还原
净额正确性sum 即为净额看似一致,但无过程记录
时点还原可回答任意日期的净额只能回答当前值
跨期处理各期报表自洽上期报表被动改写,已披露数据失真
实现复杂度需处理重复冲正表面简单,长期隐患大
冲正行要引用原交易号,才能从净额一路追回每一笔正负记录。同时要防重复冲正:同原单同类型的冲正只允许一条,可用唯一约束兜住,否则重复退款会静默把金额冲成负数。

易错点

  • 直接 update 原记录金额:审计链断裂,事后无法解释金额为何变化
  • 冲正行缺原单引用:只能看到负金额,无法定位冲的是哪一笔
  • 重复冲正无唯一约束:同一笔被冲两次,净额错成负数且不易发现
  • 冲正时间沿用原业务时间:跨月冲正把已结账月份的报表改写,对外披露数据失真
  • 对账用净额掩盖冲正量:冲正占比异常升高被平均掉,业务风险信号丢失

数据来源与参考

  • 事实表设计实践:冲正
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌