SQL如何仅对指定百分比的行应用MIN() OVER窗口函数计算最小值
实现分组排除指定比例最低值后取窗口最小值的方案
你原查询直接用MIN() OVER()取的是分组全量数据的最小值,要实现排除组内最低X%行后再取最小值,可以通过窗口百分比排名函数做中间层计算,步骤和代码如下:
核心逻辑
- 先按
deptno + job分组,组内按sal升序计算每行的百分比排名,标记每行在组内薪资从低到高的累计位置占比 - 计算最小值时,只统计百分比排名大于等于排除阈值的行,自动过滤掉前X%的最低薪资行
- 最终结果仍然保留原表所有行,和你原查询的返回行结构一致
可直接运行的代码(以排除50%最低行为例)
兼容MySQL 8.0+、PostgreSQL、Oracle、SQL Server等所有支持标准窗口函数的数据库:
WITH ranked_emp AS ( SELECT empno, ename, deptno, sal, job, -- 组内按薪资升序计算百分比排名,取值范围0~1 PERCENT_RANK() OVER (PARTITION BY deptno, job ORDER BY sal ASC) AS sal_rank_pct FROM emp ) SELECT empno, ename, deptno, sal, job, -- 阈值0.5对应排除前50%的最低薪资行,可按需调整数值 MIN(CASE WHEN sal_rank_pct >= 0.5 THEN sal END) OVER (PARTITION BY deptno, job) AS min_sal_by_dept_and_job FROM ranked_emp;
补充说明
- 调整排除比例只需要修改判断条件里的阈值即可:比如要排除最低20%的薪资行,把
0.5改成0.2就行 - 按你给出的示例场景,组内两个薪资为1250的行百分比排名低于0.5,会被排除在计算范围外,最终统计1500、1600两个值的最小值,返回结果1500,完全匹配你的预期
- 如果你的业务规则是按“薪资值的累计占比”而非“行数的累计占比”过滤,可以把
PERCENT_RANK()替换成CUME_DIST(),两者计算逻辑略有差异,可根据实际边界需求选择:PERCENT_RANK()计算规则:(当前行升序排名 - 1) / (组内总行数 - 1),组内薪资最低的行排名值固定为0CUME_DIST()计算规则:小于等于当前薪资的行数 / 组内总行数,适合需要按薪资值分布做过滤的场景
内容的提问来源于stack exchange,提问作者user3687808
相关产品推荐
相关产品推荐

