常见转换模式
数仓层间加工绝大多数落在几类模式上:按维度聚合、按主键取最新一条、维表补全、分组排名、区间累计与同环比。掌握这些写法,多数需求不需要引入额外的框架或复杂作业,也能让不同人写出的 SQL 保持一致的思路。
最容易出错的两处
一是聚合与窗口函数的执行顺序:窗口函数在 WHERE 之后执行,要过滤窗口结果必须再包一层子查询。二是维表 join 前没有去重,一行明细匹配到多行维度,行数被放大、金额被重复累计,这是汇总对不上的最高频原因。
基本信息
| 聚合模式 | GROUP BY 维度做求和、计数、去重计数 |
|---|---|
| 取最新一条 | ROW_NUMBER 按主键分组,排序后取 rn=1 |
| 维表补全 | 去重后的维度 LEFT JOIN 明细 |
| 排名与 TopN | 窗口函数按分组排序取前 N |
| 区间累计 | 窗口范围聚合(累计至当日) |
| 同环比 | LAG 取上一期数值做对比 |
模式与适用场景
| 模式 | 适用 | 要点 |
|---|---|---|
| 按维度聚合 | 日汇总、渠道汇总 | 过滤条件写在聚合之前以减少数据量 |
| 取最新一条 | 状态类明细去重 | 排序字段要与业务「最新」的定义一致 |
| 维表补全 | 补充渠道名、品类名等描述字段 | 关联前先对维表按主键去重 |
| TopN 排名 | 热销商品、活跃用户榜 | 先聚合再排名,避免在明细上直接排名 |
| 区间累计与同环比 | 累计指标、同比环比 | 用窗口函数或自关联,注意补齐缺失日期 |
典型使用场景
- 每日销售汇总:按日期与渠道聚合,供看板使用
- 用户最新状态:从变更明细中取每个用户的最新一条
- 维度补全:给订单明细补上渠道名称与地区信息
- 榜单类需求:按品类取销售额前 N 的商品
- 累计指标:当月累计成交额、累计活跃用户数
- 同环比对比:与上一期、去年同期对比,观察趋势
按维度聚合与取最新一条
按维度聚合与取最新一条
-- 按渠道每日汇总:先过滤分区,再聚合
SELECT dt, channel, SUM(amount) AS amount
FROM dwd_order
WHERE dt BETWEEN '2026-10-01' AND '2026-10-11'
GROUP BY dt, channel;
-- 每个用户最近一笔订单:窗口函数在 WHERE 之后执行,必须再包一层
SELECT * FROM (
SELECT o.*, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY ts DESC) AS rn
FROM dwd_order o WHERE dt = '2026-10-11'
) t WHERE rn = 1;维表补全与同环比
维表补全与同环比
-- 维表先去重再关联,避免行数放大导致金额重复累计
SELECT o.order_id, c.channel_name
FROM dwd_order o
LEFT JOIN (
SELECT channel_code, MAX(channel_name) AS channel_name
FROM dim_channel GROUP BY channel_code
) c ON o.channel_code = c.channel_code;
-- 同环比:用 LAG 取上一期数值,按维度分组、按时间排序
SELECT dt, channel, amount,
LAG(amount, 1) OVER (PARTITION BY channel ORDER BY dt) AS amount_prev_day
FROM dws_channel_1d; -- amount_prev_day 为 NULL 表示上一期缺失,不要当成 0过滤窗口函数结果必须使用子查询或 CTE:把 rn = 1 写在同一层的 WHERE 里,此时窗口还没计算出来,语句会直接报错或被引擎按其它语义处理。
LEFT JOIN 维表缺失时,补 NULL 还是补默认值要在链路上统一约定:两种处理混用会让下游汇总口径漂移,且很难从结果反推原因。