在电商、零售等业务系统的数据库表中,产品数据通常会包含产品类别、产品价格等字段,业务侧经常需要统计每类产品的最高价格,用于定价分析、竞品对比等场景。使用SQL的PARTITION BY子句配合窗口函数,可以快速实现这个需求,比传统的GROUP BY加子查询的方式更简洁。

基础数据表结构说明
首先我们模拟一张产品信息表product_info,表结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | int | 产品唯一ID |
| product_name | varchar(50) | 产品名称 |
| category | varchar(20) | 产品类别 |
| price | decimal(10,2) | 产品价格 |
表中部分示例数据如下:
| id | product_name | category | price |
|---|---|---|---|
| 1 | 无线鼠标 | 数码配件 | 89.00 |
| 2 | 机械键盘 | 数码配件 | 299.00 |
| 3 | 纯棉T恤 | 服饰 | 59.00 |
| 4 | 牛仔裤 | 服饰 | 129.00 |
| 5 | 保温杯 | 日用品 | 49.00 |
PARTITION BY语法基础
PARTITION BY是窗口函数的组成部分,作用是将数据按照指定字段进行分组,然后在每个分组内执行窗口函数的计算逻辑,不会像GROUP BY那样将多行数据合并成一行。提取每组最大值时,我们搭配MAX()窗口函数使用,基础语法如下:
-- 窗口函数基本语法 MAX(字段名) OVER (PARTITION BY 分组字段) AS 别名
其中PARTITION BY 分组字段表示按照该字段的值对数据进行分区,每个分区内的MAX(字段名)会计算该分区内该字段的最大值。
提取每类产品最高价的具体实现
针对上面的product_info表,要提取每类产品的最高价,只需要按照category字段分区,计算price的最大值即可,完整SQL如下:
-- 提取每类产品最高价
SELECT
id,
product_name,
category,
price,
MAX(price) OVER (PARTITION BY category) AS category_max_price
FROM product_info;
执行上述SQL后,得到的结果如下:
| id | product_name | category | price | category_max_price |
|---|---|---|---|---|
| 1 | 无线鼠标 | 数码配件 | 89.00 | 299.00 |
| 2 | 机械键盘 | 数码配件 | 299.00 | 299.00 |
| 3 | 纯棉T恤 | 服饰 | 59.00 | 129.00 |
| 4 | 牛仔裤 | 服饰 | 129.00 | 129.00 |
| 5 | 保温杯 | 日用品 | 49.00 | 49.00 |
可以看到,每个产品类别对应的category_max_price都是该类别下的最高价格,数码配件类最高价是299.00,服饰类最高价是129.00,日用品类最高价是49.00。
如果只需要保留每类最高价对应的产品行
如果业务需求是只保留每类产品里价格最高的那一条记录,可以搭配子查询和WHERE条件过滤,SQL如下:
-- 只保留每类产品最高价对应的记录
SELECT
id,
product_name,
category,
price
FROM (
SELECT
id,
product_name,
category,
price,
MAX(price) OVER (PARTITION BY category) AS category_max_price
FROM product_info
) t
WHERE price = category_max_price;
如果同一类别下有多个产品价格都等于最高价,上述SQL会返回所有符合条件的记录。如果只需要返回一条,可以再添加ROW_NUMBER()窗口函数排序后取第一条。
和传统实现方式对比
传统方式提取每类产品最高价,通常需要先按类别分组计算最高价,再和原表关联,SQL如下:
-- 传统GROUP BY加子查询实现
SELECT
p.id,
p.product_name,
p.category,
p.price,
t.max_price AS category_max_price
FROM product_info p
JOIN (
SELECT category, MAX(price) AS max_price
FROM product_info
GROUP BY category
) t ON p.category = t.category;
对比两种方式,使用PARTITION BY的窗口函数不需要额外的表关联,代码逻辑更清晰,执行效率在大部分场景下也更高,尤其是数据量较大的时候,减少关联操作能明显降低查询耗时。
注意事项
- PARTITION BY子句支持多个字段分组,比如需要按类别和品牌同时分组取最高价,可以写成
PARTITION BY category, brand。 - 窗口函数中的
ORDER BY子句不会影响MAX()的计算结果,除非搭配ROWS或者RANGE框架使用,提取最大值时一般不需要添加ORDER BY。 - 不是所有数据库都支持窗口函数,MySQL 8.0及以上、PostgreSQL、SQL Server、Oracle等主流数据库都支持,低版本MySQL需要先确认版本兼容性。
SQLPARTITION_BY分组取最大窗口函数修改时间:2026-07-11 21:27:29