工作笔记 - PG分组极值

概述

笔者在工作的过程中,遇到一个比较典型的问题,就是需要查找分组记录中的某个极值所对应的记录。

一个经典的场景就是学生科目成绩表。分组的依据是科目。想要查询各个科目成绩最好的学生记录(假设没有并列排名)。

比较传统的方式是分组聚合(Group By) ,查到分组中的最高分,然后倒查学生记录。

还有一种方式是使用窗口函数( Rank() over ... ),找到记录在窗口中对应的排序,然后取各个窗口序号为一的那条记录。

笔者觉得这两种方式对于这个简单的需求而言,都过于繁琐。 经过和AI的讨论,发现了一种看起来比较简洁的技术方案。觉得有点意思,处理的思路也很有启发,遂著文记录和分享之。

技术方案

简单而言,这个技术方案的核心SQL是:

"Distinct ON(field)"

它可以处理重复字段值,也就是记录分组,并保留记录其他字段的值。

下面是完整的示例:

sql 复制代码
SELECT DISTINCT ON (course) stuid, course, score, examtime 
FROM scores 
ORDER BY course, score desc

// 还可以写成

SELECT DISTINCT ON (course) * FROM scores 
ORDER BY course, score desc

假设这里分组的依据是科目 course, 这个查询就可以查出分组中,按照分数倒排第一记录,当然包括学生的ID和其他其他信息。最后再对course进行汇总,就查询出所有科目的第一名学生的信息了。

简单总结一下用法:

  • distinct on () 用于指定分组的依据,所谓分组,就是字段值相同的记录的集合,它使用重复值来进行处理
  • 后面可选要提取的字段,也可以是 *
  • 关键是排序方式,因为这里的场景比较简单,就是取排序中的极值,所以先按分组排序,然后按值排序

这个查询笔者是在Postgres中调试和通过的,其他SQL系统的支持和实现情况未知。

小结

本文探讨和记录了一种不使用聚合查询和窗口函数来查询分组极值记录的一种方式。已经在笔者的一个应用中使用,觉得值得分享和探讨。

相关推荐
mCell5 小时前
你以为短链接只是 Hash + 301/302?
后端·算法·架构
咖啡八杯6 小时前
GoF设计模式——迭代器模式
java·后端·设计模式·迭代器模式
小二·7 小时前
RAG + 向量数据库实战:ChromaDB / Milvus / FAISS 选型与性能横评
数据库·milvus·faiss
矜持的左手7 小时前
电子小白的枕边书:电子学(The Art of Electronics)
数据库·restful
吴声子夜歌7 小时前
Redis 5.x——布隆过滤器
数据库·redis·缓存
蓝天下的守望者8 小时前
svt_apb_if里的宏定义问题
运维·服务器·数据库
上海云盾-小余8 小时前
网站频繁遭遇 SQL 注入溯源与原生漏洞修复全流程总结
数据库·sql
数据库小学妹8 小时前
国家区域医疗中心国产化改造实战:数据库选型、跨院区数据互通与踩坑经验
数据库·国产数据库·数据库选型·医疗信息化·信创数据库·医疗信创
IT_陈寒10 小时前
SpringBoot自动配置不是你以为的那样的智能
前端·人工智能·后端