苹果和桔子每天的销量差:不要依赖行的顺序
LeetCode 1445 · 条件聚合、带符号求和、窗口函数的确定性
面试怎么回答
按 sale_date 分组,SUM(CASE WHEN fruit = 'apples' THEN sold_num ELSE -sold_num END)。不用 LEAD,因为窗口里不写 ORDER BY 时行序不确定,苹果的下一行未必是桔子;条件求和不依赖顺序,某天缺一种水果也能算对。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
销售表记录每天苹果和桔子各卖了多少(每天两种水果各一行)。输出每天苹果销量减桔子销量的差,按日期排序。
表结构
- Sales:sale_date、fruit(apples / oranges)、sold_num;(sale_date, fruit) 为主键
思路
最稳妥的写法是按日期分组,苹果记正、桔子记负,求和就是差值。原解法用 LEAD 在同一天的两行之间取「下一行」,但窗口里没写 ORDER BY,同一天两行谁在前不确定,苹果那行的「下一行」不一定是桔子,结果可能是错的。
参考解法
select sale_date,sold_num-ld diff
from
(
select sale_date,sold_num , fruit ,lead(sold_num ,1,null) over(partition by sale_date ) ld
from Sales
)t1
where fruit='apples'
另一种写法:按日期分组的带符号求和
SELECT sale_date, SUM(IF(fruit = 'apples', sold_num, -sold_num)) AS diff
FROM Sales
GROUP BY sale_date
ORDER BY sale_date
易错点
- 窗口函数没有 ORDER BY 时,分区内行的顺序是不确定的,LEAD / LAG 的结果也就不确定。
- 某天只卖了一种水果时,LEAD 写法会得到 NULL,条件求和写法能正确算出差值。