如何通过SQL查询获取每月各产品的最低价记录
获取每月各产品最低价记录的SQL解决方案
嘿,我来帮你搞定这个查询需求!先理清楚你的场景:
你有一张product_prices表,结构和数据是这样的:
| ID | Product_id | Price | Price_date |
|---|---|---|---|
| 1 | 1 | 5 | 2021-10-01 |
| 2 | 1 | 6 | 2021-10-25 |
| 3 | 2 | 5 | 2021-10-01 |
| 4 | 2 | 6 | 2021-10-25 |
| 5 | 1 | 3 | 2021-09-01 |
| 6 | 1 | 5 | 2021-09-25 |
| 7 | 2 | 7 | 2021-09-01 |
| 8 | 2 | 3 | 2021-09-25 |
你需要找出每个月份里,每个产品对应的最低价记录,期望得到的结果是这样的:
| ID | Product_id | Price | Price_date |
|---|---|---|---|
| 1 | 1 | 5 | 2021-10-01 |
| 3 | 2 | 5 | 2021-10-01 |
| 5 | 1 | 3 | 2021-09-01 |
| 8 | 2 | 3 | 2021-09-25 |
下面给你两种实用的解决方案,你可以根据自己用的数据库选择:
方案一:用窗口函数ROW_NUMBER()(推荐)
这个方法清晰又高效,适合支持窗口函数的数据库(比如MySQL 8.0+、PostgreSQL、SQL Server、Oracle等)。核心思路是给每个产品的每月记录按价格排序,取最低价的那条:
SELECT ID, Product_id, Price, Price_date FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY DATE_FORMAT(Price_date, '%Y-%m'), Product_id ORDER BY Price ASC, Price_date ASC ) AS rn FROM product_prices ) AS ranked WHERE rn = 1;
给你拆解下这段代码:
DATE_FORMAT(Price_date, '%Y-%m'):把日期转成年-月格式,这样就能按月份分组啦。如果是SQL Server可以换成FORMAT(Price_date, 'yyyy-MM'),Oracle用TO_CHAR(Price_date, 'YYYY-MM'),根据你的数据库调整就行。PARTITION BY:按「年份月份+产品ID」分组,这样每个产品每个月的记录会被分到一个组里。ORDER BY Price ASC, Price_date ASC:先按价格升序排,确保最低价排在最前面;如果同一个月同一个产品有多个相同最低价,就按日期升序取最早的那条(要是想取最晚的,把Price_date ASC改成DESC就行)。WHERE rn = 1:筛选出每个组里排名第一的记录,也就是我们要的最低价记录。
方案二:子查询分组(兼容老版本数据库)
如果你用的是不支持窗口函数的老版本数据库(比如MySQL 5.x),可以用这个方法:先通过子查询算出每个月份每个产品的最低价,再关联原表拿到完整记录:
SELECT p.ID, p.Product_id, p.Price, p.Price_date FROM product_prices p JOIN ( SELECT DATE_FORMAT(Price_date, '%Y-%m') AS month, Product_id, MIN(Price) AS min_price FROM product_prices GROUP BY month, Product_id ) AS m ON DATE_FORMAT(p.Price_date, '%Y-%m') = m.month AND p.Product_id = m.Product_id AND p.Price = m.min_price;
注意:
这个方法如果遇到同一月份同一产品有多个相同最低价的记录,会返回所有符合条件的记录;而窗口函数的方法可以通过排序规则控制只返回一条。你可以根据自己的实际需求选择。
内容的提问来源于stack exchange,提问作者Sergey Vershinin Yazzi
相关产品推荐
相关产品推荐

