如何获取SQL分组排序结果中80%位置的行数据?
获取分组排序后80%位置的行
要实现从你的分组求和结果中提取处于总行数80%位置的行,核心是先确定总行数,再定位目标行的位置。下面针对不同主流SQL数据库给出具体方案:
通用窗口函数方案(支持MySQL 8.0+、PostgreSQL、SQL Server等)
利用CTE(公共表表达式)先获取分组求和的结果,再通过窗口函数计算每行的行号和总行数,最后筛选目标行:
WITH grouped_data AS ( -- 你的原分组求和查询 SELECT TICKETID, SUM(IMPACT) AS S FROM incident GROUP BY TICKETID ORDER BY S ), ranked_data AS ( SELECT TICKETID, S, ROW_NUMBER() OVER(ORDER BY S) AS row_num, -- 按S排序生成行号 COUNT(*) OVER() AS total_rows -- 计算分组后的总行数 FROM grouped_data ) SELECT TICKETID, S FROM ranked_data -- 匹配80%位置的行,这里用CAST取整数部分,对应你例子中5行取第4行 WHERE row_num = CAST(total_rows * 0.8 AS INTEGER);
说明:
- 如果总行数×80%不是整数(比如6行时6×0.8=4.8),可以根据需求调整:
- 用
FLOOR(total_rows * 0.8)取向下取整的位置(比如4.8取4,对应第4行) - 用
CEIL(total_rows * 0.8)取向上取整的位置(比如4.8取5,对应第5行)
- 用
MySQL 5.x兼容方案(无窗口函数支持)
如果你的MySQL版本不支持窗口函数,可以用用户变量来实现:
SELECT TICKETID, S FROM ( SELECT g.TICKETID, g.S, @row_num := @row_num + 1 AS row_num, @total_rows AS total_rows FROM ( -- 原分组求和查询 SELECT TICKETID, SUM(IMPACT) AS S FROM incident GROUP BY TICKETID ORDER BY S ) g, -- 初始化变量:行号从0开始,总行数为分组后的记录数 (SELECT @row_num := 0, @total_rows := (SELECT COUNT(*) FROM (SELECT 1 FROM incident GROUP BY TICKETID) t)) vars ) ranked WHERE row_num = CAST(total_rows * 0.8 AS INTEGER);
PostgreSQL专属分页方案
PostgreSQL可以结合OFFSET和LIMIT直接定位目标行,写法更简洁:
WITH grouped_data AS ( SELECT TICKETID, SUM(IMPACT) AS S FROM incident GROUP BY TICKETID ORDER BY S ), total_count AS ( SELECT COUNT(*) AS cnt FROM grouped_data ) SELECT gd.TICKETID, gd.S FROM grouped_data gd, total_count tc ORDER BY gd.S -- OFFSET从0开始,所以要减1;用GREATEST避免总行数为1时出现负数OFFSET OFFSET GREATEST(CAST(tc.cnt * 0.8 AS INTEGER) - 1, 0) LIMIT 1;
内容的提问来源于stack exchange,提问作者Veljko
相关产品推荐
相关产品推荐

