题目重点:按类型聚合净收入,取前三类型并算相对所有类型的收入占比。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练Top3按completed net_revenue排名,不是订单数;exactly3 types、tie按type名称。题面“popular”若指订单数,要替换排名依据,不自动假定收入。
- 每餐厅唯一type,一行一order;净收入与币种已统一,分母所有类型净收入而非前三之和。
解题路线
- 一个CTE按restaurant_type SUM收入,窗口SUM(revenue) OVER()在LIMIT之前计算全体类型总收入。最终ORDER BY revenue DESC,type LIMIT3,逻辑顺序保证分母未被Top3过滤。
- 如果先LIMIT3子查询再窗口sum,会把占比归一成前三内部份额,丢失对overall的比较;两者回答不同问题。
- exact3与包含并列第三名不同。需要包含tie则DENSE_RANK或RANK按明确政策,不能加type排序到rank里消除tie。
- cancelled排除,refund/gross/net若由独立事实提供先定义金额。总体净收入0用NULLIF返回NULL,负收入也可能使“份额”超常见0..1范围,需按财务口径解释。
手动走一遍
A/B/C/D收入40/30/20/10,前三占比0.4/0.3/0.2,总0.9,不是4/9、3/9、2/9。两类型同收入只取3时名称确定排序;含并列第三政策可能返回4行。
SQL 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
-- Training: top three TYPES by completed net revenue, not three individual restaurants.
-- Exact 3 rows (if available), ties broken type name. Share denominator ALL types.
WITH type_revenue AS (
SELECT r.restaurant_type, SUM(o.net_revenue) AS revenue
FROM orders o JOIN restaurant r ON r.restaurant_id=o.restaurant_id
WHERE o.status='completed'
GROUP BY r.restaurant_type
)
SELECT restaurant_type, revenue,
1.0 * revenue / NULLIF(SUM(revenue) OVER (),0) AS overall_revenue_share
FROM type_revenue
ORDER BY revenue DESC, restaurant_type ASC
LIMIT 3;
复杂度
事实join/group需扫描O订单,T类型排序O(T log T),窗口总和O(T)。一个CTE足够表达粒度转换,但少CTE不等于计划一定更快,应按实际执行计划验证。
易错点与追问
容易失分的边界
- 全体分母在LIMIT之后计算,百分比口径被偷换。
- Top3餐厅与Top3类型混为一谈。
继续深挖
- 如果每餐厅多type标签,是否全分配或按权重分配收入?需bridge表和计数政策。
- 排名按订单数但占比按收入时,query要保存两个独立指标。
