Partition By与LAG函数使用疑问:如何获取对应维度的上月金额
你必须修改Partition By子句,加入ID和Product才能正确获取对应ID、Product的上月金额,只按Name分区会得到完全不符合预期的结果。
为什么只按Name分区不行?
Partition By的核心作用是把数据集切割成独立的分组,窗口函数(比如LAG)只会在当前分组内部查找前一行数据。如果只写Partition By Name,所有名为Jason的记录会被归到同一个分组里,再按Date排序的话,所有Jan 2017的记录(不管ID和Product是什么)都会排在Feb 2017的记录前面。
举个实际执行结果的例子,第一种SQL语句:
Select Name, ID, Product, Date, Amount, LAG(Amount,1) Over (Partition By Name Order by Date) FROM table
得到的结果会是:
| Name | ID | Product | Date | Amount | LAG结果 |
|---|---|---|---|---|---|
| Jason | 1 | Car | Jan 2017 | $10 | NULL |
| Jason | 2 | Car | Jan 2017 | $50 | $10 |
| Jason | 3 | House | Jan 2017 | $20 | $50 |
| Jason | 1 | Car | Feb 2017 | $5 | $20 |
| Jason | 2 | Car | Feb 2017 | $60 | $5 |
| Jason | 3 | House | Feb 2017 | $30 | $60 |
你会发现,ID为1、Product为Car的Feb 2017记录,它的LAG值是$20——这是ID为3、Product为House的Jan记录金额,完全不是你想要的对应ID+Product的上月数据。
加入ID和Product后的正确效果
当你把Partition By改成Name, ID, Product后,每个分组就变成了「同一个Name+ID+Product」的独立组合,每个分组内部只有该组合的Jan和Feb记录,按Date排序后,LAG函数就能精准取到同一组合的上月金额。
对应的SQL语句:
Select Name, ID, Product, Date, Amount, LAG(Amount,1) Over (Partition By Name, ID, Product Order by Date) FROM table
执行结果如下:
| Name | ID | Product | Date | Amount | LAG结果 |
|---|---|---|---|---|---|
| Jason | 1 | Car | Jan 2017 | $10 | NULL |
| Jason | 1 | Car | Feb 2017 | $5 | $10 |
| Jason | 2 | Car | Jan 2017 | $50 | NULL |
| Jason | 2 | Car | Feb 2017 | $60 | $50 |
| Jason | 3 | House | Jan 2017 | $20 | NULL |
| Jason | 3 | House | Feb 2017 | $30 | $20 |
这样每个ID+Product组合的Feb记录,都能准确获取到自己上月的金额,完全符合你的需求。
总结
窗口函数的分区逻辑一定要匹配你的业务需求——你需要的是「同一个用户下的同一个ID+Product组合」的上月数据,所以分区键必须包含Name, ID, Product这三个字段,才能确保分组的准确性,让LAG函数在正确的范围内查找前一行数据。
内容的提问来源于stack exchange,提问作者JohnRambo

