如何编写SQL查询获取每个SalesId的最新销售日期记录
分组获取每个SalesId的最新销售记录解法
这是个很常见的业务需求,我给你两种实用的解决方案,适配不同的数据库环境:
先明确问题背景
假设我们有一张名为sales的销售表,结构和数据如下:
| SalesId | ItemId | DateSale | USDVal |
|---|---|---|---|
| ABC | 01A | 2018-04-01 | 52 |
| ABC | 01B | 2018-04-01 | 300 |
| ABC | 01C | 2018-04-01 | 12 |
| ABC | 01D | 2018-04-01 | 62 |
| ABC | 01A | 2018-03-23 | 66 |
| MNB | 01A | 2018-01-01 | 584 |
| MNB | 01A | 2018-02-20 | 320 |
| MNB | 01F | 2018-02-20 | 5 |
我们需要筛选出每个SalesId对应的最新销售日期的所有记录,最终结果要包含该日期下的所有条目(比如ABC的4条2018-04-01的记录都要保留)。
方法1:窗口函数法(推荐,支持现代数据库)
如果你的数据库支持SQL窗口函数(比如MySQL 8+、PostgreSQL、SQL Server、Oracle等),用RANK()函数是最简洁直观的方式:
SELECT SalesId, ItemId, DateSale, USDVal FROM ( SELECT SalesId, ItemId, DateSale, USDVal, -- 按SalesId分组,每组内按日期倒序排名,同日期的记录排名相同 RANK() OVER (PARTITION BY SalesId ORDER BY DateSale DESC) AS rnk FROM sales ) AS ranked_sales WHERE rnk = 1;
为什么用RANK而不是ROW_NUMBER?
ROW_NUMBER()会给同日期的不同条目分配不同的序号(比如1、2、3...),这样只会保留一条记录,不符合我们要保留所有同日期条目的需求。RANK()会给同一SalesId下相同最新日期的所有记录分配排名1,这样就能一次性筛选出所有符合要求的条目。
方法2:子查询关联法(兼容旧版数据库)
如果你的数据库不支持窗口函数(比如MySQL 5.x),可以用子查询先找出每个SalesId的最新日期,再关联原表获取对应记录:
SELECT s.SalesId, s.ItemId, s.DateSale, s.USDVal FROM sales s INNER JOIN ( -- 先算出每个SalesId的最新销售日期 SELECT SalesId, MAX(DateSale) AS latest_date FROM sales GROUP BY SalesId ) AS latest_dates -- 关联条件:SalesId匹配,且记录日期等于该SalesId的最新日期 ON s.SalesId = latest_dates.SalesId AND s.DateSale = latest_dates.latest_date;
这种方法逻辑清晰,兼容性强,同样能得到符合预期的结果。
内容的提问来源于stack exchange,提问作者mHelpMe




