首页/数据/数仓建模速查/示例:交易域订单事实建模
建模基础69 条

示例:交易域订单事实建模

订单过程常见两粒度:订单头(一笔订单一行)与订单明细行;两者分别建事实表并通过退化维度订单号关联,避免粒度混杂。

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

订单过程怎么分粒度

交易域的订单通常有两个自然粒度:订单头(一笔订单一行)和订单明细行(一笔订单中的一个商品行一行)。两者分别建事实表,用订单号作为退化维度关联,避免把两种粒度塞进一张表造成金额重复计算。

基本信息

头粒度一行 = 一笔订单,承载订单级金额与状态
行粒度一行 = 一个订单商品行,承载数量、单价、行金额
关联键订单号作为退化维度直接存在事实表中
常用维度日期、用户、商品、门店、渠道、促销
口径注意头级优惠分摊到行需要明确规则

典型使用场景

  • 订单量统计:按头粒度计算订单笔数,行粒度会得到商品行数
  • 销售额统计:按行粒度汇总金额,可下钻到商品与类目
  • 客单价分析:订单金额除以订单笔数,两个粒度各自提供一半数据
  • 履约时效:头表的各里程碑时间用于计算发货与签收耗时
  • 优惠归因:头级优惠需要按规则分摊,才能得到行级真实成交价

头行两表查询

头行两表查询
-- 头表:一笔订单一行,用于订单笔数与订单级金额
-- fact_order(order_id, user_sk, order_date_key, order_amt, status)

-- 行表:一个商品行一行,用于商品级与类目级汇总
-- fact_order_item(order_id, product_sk, qty, item_amt, discount_amt)

SELECT p.cat_l1_name,
       sum(i.qty)        AS sale_qty,     -- 行级数量
       sum(i.item_amt)   AS sale_amt      -- 行级金额,不含头级优惠
FROM fact_order_item i
JOIN dim_product p ON i.product_sk = p.product_sk
WHERE i.dt = '2026-10-12'
GROUP BY p.cat_l1_name;

-- 订单笔数必须从头表取,直接对行表 count 会得到商品行数
-- SELECT count(DISTINCT order_id), count(1) FROM fact_order_item WHERE dt='2026-10-12';

头行两表对照

对比项订单头事实表订单明细行事实表
粒度一笔订单一行一个商品行一行
主要度量订单金额、优惠、状态数量、单价、行金额
典型分析订单量、客单价、履约品类销售、商品排行
关联方式订单号作为退化维度订单号关联回头表
头级与行级度量不能混算:把订单级优惠与行级金额放在同一个 sum 里,会按行数重复计入优惠。优惠要不要分摊、按什么规则分摊,是必须在文档里写明的口径决策。
头表与行表通过订单号关联做明细查询时,如果行表存在重复行(同一商品行被重复投递),订单级金额会被成倍放大。关联前先确认行表已按业务主键去重。

易错点

  • 头行混在一张表,按行汇总时订单级金额被重复计算,销售额虚高数倍
  • 优惠分摊规则缺失,行级金额合计与头表金额对不上,财务侧无法对账
  • 用行表统计订单笔数而忘记 DISTINCT,订单量与商品行数混为一谈
  • 头表与行表的状态字段独立更新,出现行已发货而头表仍待发货的口径矛盾

数据来源与参考

  • 交易域建模实践
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌