SQL如何基于另一列条件筛选分组后某列取最小值的行
SQL按分组筛选指定列最小值对应行的实现方案
需求规则
根据给出的表结构和查询要求,核心规则如下:
- 基础分组维度为
PersonID、ConsultantID - 每组内优先取
EpisodeNumber最小的整行数据 - 同一
PersonID下存在不同Diagnosis需单独区分统计
推荐解法:窗口函数法
支持MySQL 8.0+、PostgreSQL、SQL Server、Oracle等所有支持窗口函数的现代数据库,写法简洁性能稳定:
WITH ranked_data AS ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY PersonID, ConsultantID, Diagnosis ORDER BY CAST(EpisodeNumber AS UNSIGNED) ASC ) AS rank_num FROM Persons ) SELECT PersonID, Diagnosis, ConsultantID, EpisodeNumber FROM ranked_data WHERE rank_num = 1;
注意点说明
- 由于示例表中
EpisodeNumber定义为varchar类型,排序时通过CAST转为数值类型,避免字符串排序出现'10' < '2'的逻辑异常,如果你的实际表中该字段为数值类型可直接省略转换步骤 PARTITION BY后增加Diagnosis字段,实现同一用户、同一医生下不同诊断的单独分组,符合区分不同诊断的需求- 如果同一分组内存在多条
EpisodeNumber相同的最小值行,希望全部返回时,可将ROW_NUMBER()替换为RANK()函数
低版本数据库兼容解法
如果使用不支持窗口函数的低版本数据库(如MySQL 5.x),可使用子查询关联的方式实现:
SELECT p.* FROM Persons p INNER JOIN ( SELECT PersonID, ConsultantID, Diagnosis, MIN(CAST(EpisodeNumber AS UNSIGNED)) AS min_episode FROM Persons GROUP BY PersonID, ConsultantID, Diagnosis ) t ON p.PersonID = t.PersonID AND p.ConsultantID = t.ConsultantID AND p.Diagnosis = t.Diagnosis AND CAST(p.EpisodeNumber AS UNSIGNED) = t.min_episode;
执行结果
两种方法执行后得到的结果与预期一致,最终返回数据如下:
| PersonID | Diagnosis | ConsultantID | EpisodeNumber |
|---|---|---|---|
| 1 | Headache | 001 | 1 |
| 1 | Stomachache | 002 | 1 |
| 2 | Headache | 003 | 1 |
| 3 | Hand | 004 | 1 |
| 3 | Headache | 003 | 1 |
内容的提问来源于stack exchange,提问作者DON_DON
相关产品推荐
相关产品推荐

