用窗口函数算出排名与趋势
目标
使用 row_number、rank、dense_rank、累计和、lag、占比、ntile 计算排名和趋势,并判断何时使用窗口函数。
为什么重要
聚合会折叠行并丢失单行信息,但许多问题需要在保留每行时引用周边数据。窗口函数正好解决这一问题。自连接和相关子查询也能实现,但代码更长且要多次读表。
请记住:窗口函数结果不能用于同一个 SELECT 的 WHERE。 WHERE 在处理顺序中更早执行,因此按排名筛选时必须再套一层子查询或 CTE。
步骤
- 商品按类别内价格降序排列,并在并列时按
id升序,为该序号创建视图v_ranked_products。列为category、id、price、rn。 - 创建视图
v_rank_compare,用两种方式对全部商品按价格降序排名。列为id、price、rnk、drnk。 - 创建视图
v_running_revenue,保存月度销售额与累计额。列为month、revenue、cum_revenue,月份基准为AT TIME ZONE 'Asia/Seoul'。 - 创建视图
v_mom。列为month、revenue、prev_revenue、diff,首月prev_revenue为空。 - 创建视图
v_channel_share。列为channel、revenue、share_pct,比例保留两位且合计 100。 - 创建视图
v_top3_per_category,列为category、id、price。 - 商品按价格升序排列,并列时按
id升序,将其四等分后创建视图v_price_quartile。列为id、price、quartile。 - 创建视图
v_first_order,列为customer_id、order_id、ordered_at;时间相同时,以id较小者为首单。
参考
- 基本形式:
함수() OVER (PARTITION BY 그룹 ORDER BY 정렬) OVER ()表示整个结果集是一个窗口。- 排名结果不能用于同一个 SELECT 的 WHERE。
- 排序存在并列时,请加入 tie-break 列。
按类别标记价格序号
商品按类别内价格降序排列,并在并列时按 id 升序,为该序号创建视图 v_ranked_products。列为 category、id、price、rn。
同时使用划分窗口的子句和确定窗口内部顺序的子句。并列时用 id 区分。
比较两种排名函数
创建视图 v_rank_compare,用两种方式对全部商品按价格降序排名。列为 id、price、rnk(并列后跳号)、drnk(不跳号)。
有一个函数会在并列后跳过名次,另一个不会。
计算累计销售额
创建视图 v_running_revenue,保存已完成订单的月度销售额和累计销售额。列为 month、revenue、cum_revenue,月份基准为 AT TIME ZONE 'Asia/Seoul'。
先生成月度汇总,再在其结果上打开窗口。顺序相反会把聚合与窗口混在一起。
计算环比增减
创建视图 v_mom,在相同月度汇总上增加上月销售额和增减值。列为 month、revenue、prev_revenue、diff,第一个月的 prev_revenue 必须为空。
有一个函数可以获取上一行的值。第一个月没有前值,因此应为空。
计算占总额比例
创建视图 v_channel_share,保存各渠道销售额及其占总额比例。列为 channel、revenue、share_pct,比例四舍五入到小数点后两位,合计应为 100。
OVER 括号留空时,整个结果集是一个窗口,无需运行两次查询。
选出每组前 3 名
创建视图 v_top3_per_category,保存每个类别价格最高的 3 个商品。列为 category、id、price。
窗口函数结果不能用于同一个 SELECT 的 WHERE,必须再套一层。
划分价格四分位组
商品按价格升序排列,并列时按 id 升序,将其四等分后创建视图 v_price_quartile。列为 id、price、quartile。
有一个函数可以把行等分为 n 组并编号。请准确设置排序条件。
查找每位客户的第一张订单
创建视图 v_first_order,保存每位客户的第一张订单。列为 customer_id、order_id、ordered_at;时间相同时,以 id 较小的订单为第一张。
按客户为订单依时间编号,只保留第一条。没有订单的客户不应出现。