桥接表处理多值维度
当一条事实对应多个维度成员时(一笔订单用了多张优惠券、一个客户打了多个标签),事实与维度之间是多对多关系。直接连接会让事实行被复制:一笔 100 元的订单关联 3 张券,金额就被算成 300。桥接表(bridge table)在两者之间存关系行,通常带一个权重用于按主次分摊度量,这样既能做“命中哪些券”的覆盖分析,也能做“按券分摊金额”的贡献分析。若只需要命中关系而不需要分摊,用无事实事实表更简单。
基本信息
| 解决的问题 | 一条事实对应多个维度成员(多对多) |
|---|---|
| 结构 | 事实代理键 × 维度代理键,可加权重列 |
| 权重作用 | 按主次分配度量,避免金额被重复累加 |
| 替代方案 | 在维表存数组或字符串列表,简化查询但分析能力受限 |
| 粒度要求 | 桥接表一行代表一条关系,需在表说明中写明 |
典型使用场景
- 订单与优惠券:一笔订单使用多张券,需要同时做覆盖与金额分摊
- 商品与标签:一个商品属于多个标签,分析标签维度的销售表现
- 处方与药品:一张处方包含多种药品,统计药品用量与费用分摊
- 企业与行业分类:一家企业隶属多个行业,需按行业做加权统计
- 内容与人群包:一篇内容投放进多个人群包,评估各包的贡献
桥接表结构
桥接表结构
-- 桥接表:一行一条 订单与优惠券 的关系,权重用于分摊金额
CREATE TABLE bridge_order_promo (
order_sk BIGINT,
promo_sk INT,
weight DECIMAL(5,2) -- 分摊权重,同一 order_sk 的权重之和应为 1
);
-- 按权重分摊订单金额
SELECT p.promo_name,
SUM(f.pay_amount * b.weight) AS allocated_amt
FROM fact_order f
JOIN bridge_order_promo b ON f.order_sk = b.order_sk
JOIN dim_promo p ON b.promo_sk = p.promo_sk
GROUP BY p.promo_name;
-- 覆盖口径(只关心命中):不计权重,按主体去重
SELECT COUNT(DISTINCT b.order_sk) AS order_cnt FROM bridge_order_promo b;两种口径对照
| 口径 | 连接方式 | 结果含义 | 注意点 |
|---|---|---|---|
| 覆盖分析 | 桥接表连接后按主体去重 | 命中该维度的主体数 | 不要直接 SUM 金额 |
| 分摊分析 | 按权重加权求和 | 各维度按主次分摊的度量 | 权重之和需归一到 1 |
| 简单命中 | 无事实事实表 | 只有关系,无度量 | 实现最简单 |
不设权重直接连接桥接表会把订单金额按券数量重复计算:做覆盖分析时按主体去重,做金额分析时必须用权重。
权重之和不为 1 时,分摊后的金额合计与订单总额不一致;建模时要加一条校验,把偏离超过容差的订单找出来。
每个聚合场景各建一张桥接表会让关系口径分叉:优先用一张桥接表加权重适配多种口径,确有必要再拆分。