当前位置: 首页
数据库
SQL如何获取分组中第一条或最后一条记录_利用FIRST_VALUE函数

SQL如何获取分组中第一条或最后一条记录_利用FIRST_VALUE函数

热心网友 时间:2026-04-24
转载

SQL如何获取分组中第一条或最后一条记录:利用FIRST_VALUE函数

SQL如何获取分组中第一条或最后一条记录_利用FIRST_VALUE函数

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

为什么FIRST_VALUE返回的不是“每组第一条记录”?

很多朋友第一次用FIRST_VALUE窗口函数时,都会遇到一个困惑:结果怎么和想的不一样?它确实按你指定的顺序,取到了窗口里的第一个值,但问题是——它把那个值“复制”给了组里的每一行,行数一点没少。这就像给团队每个人都发了一份队长的名片,但队长本人并没有被单独请出来。而我们实际业务中想要的,往往是“每组只留一条代表记录”,比如最新的那笔订单、最早的那次登录、分数最高的那位学生。这时候你就会发现,FIRST_VALUE更像是个辅助工具,单靠它,解决不了“提取整行数据”这个核心问题。

怎么用FIRST_VALUE配合ROW_NUMBER拿到完整记录?

那么,正确的“组合拳”该怎么打呢?核心思路其实很清晰:分两步走。第一步,用ROW_NUMBER()给每个分组内的行,按照你的排序规则(比如时间倒序)编上号(1,2,3…)。第二步,在外层查询里,轻松地WHERE rn = 1,只把每组的“1号”选手筛选出来。在这个过程中,FIRST_VALUE可以作为一个验证字段出现,但它不是筛选的主力。

这里有三个关键点必须注意:

  • 排序是灵魂ORDER BY子句必须明确写在OVER()里面,否则ROW_NUMBER的编号顺序就是不确定的,结果自然不可靠。
  • 分组要对齐PARTITION BY里的字段(比如user_id),必须和你想分组的逻辑完全一致。
  • “最后一条”怎么取:很简单,把ORDER BY created_at DESC改成ASC就行了。当然,你也可以用LAST_VALUE,但要小心它的默认窗口范围,最好显式指定为RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,以免出错。

来看一个经典例子(获取每个用户的最新订单):

SELECT order_id, user_id, amount, created_at
FROM (
  SELECT order_id, user_id, amount, created_at,
         ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS rn
  FROM orders
) t
WHERE rn = 1;

FIRST_VALUE在SELECT里直接用有哪些陷阱?

如果把FIRST_VALUE当成“取一行”的函数来用,很容易踩坑。因为它本质上是个“填充”函数,不负责删减行数。下面这几种情况,就是典型的误用:

  • 场景一:想找“每组金额最高的订单号”。如果直接写FIRST_VALUE(order_id) OVER (PARTITION BY user_id ORDER BY amount DESC),结果会是每一行都显示同一个最高的订单号,但你却看不到这个订单对应的金额、时间等其他信息。这显然不是我们想要的完整记录。
  • 场景二:忘了写ORDER BY。这时数据库可能会按物理存储顺序来排,每次执行的结果都可能不同,毫无稳定性可言。
  • 场景三:在聚合查询里混用。窗口函数和GROUP BY聚合不能直接放在同一层SELECT中,否则要么报错,要么语义变得混乱不清。

所以,更稳妥的做法是:要么先用子查询或CTE把窗口计算的结果准备好,再去做关联查询;要么就坚持使用ROW_NUMBER配合过滤的方案,思路直观,控制力也强。

MySQL 8.0+ 和 PostgreSQL 的行为差异要点

虽然主流数据库都支持这些窗口函数,但魔鬼藏在细节里,跨平台使用时尤其要注意:

  • MySQL 8.0+ 更“较真”:它对ORDER BY子句里的表达式要求更严格。比如,你不能直接使用SELECT列表里定义的别名(像ORDER BY dt),必须写原始字段名或列位置。
  • PostgreSQL 处理空值更灵活:它支持ORDER BY ... NULLS FIRST/LAST语法,让你能明确控制空值排在前面还是后面,这在MySQL里目前还不行。
  • SQL Server 有“捷径”:在某些简单场景下,使用TOP 1 WITH TIES配合FETCH NEXT子句,写起来可能比窗口函数更简短。但这种方法不具备跨多个分组分别取第一条的能力,功能上还是有区别的。

总的来说,如果考虑代码的兼容性和可读性,ROW_NUMBER方案是更安全的选择。而FIRST_VALUE,更适合扮演一个“锦上添花”的角色,用来生成一些派生字段,不建议让它承担核心的数据筛选逻辑。

来源:https://www.php.cn/faq/2338466.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
mysql如何限制单条SQL执行消耗的内存_调整sort_buffer_size与join_buffer

mysql如何限制单条SQL执行消耗的内存_调整sort_buffer_size与join_buffer

MySQL内存调优实战:如何精准控制单条SQL的内存消耗? 说到MySQL性能调优,sort_buffer_size和join_buffer_size这两个参数总是绕不开的话题。很多工程师的第一反应是:“调大点是不是就能快些?” 事情可没这么简单。盲目调整不仅可能毫无收益,甚至还会引发内存溢出(OO

时间:2026-04-24 22:04
Redis发布订阅支持消息类型自定义吗_通过序列化与反序列化规范消息结构

Redis发布订阅支持消息类型自定义吗_通过序列化与反序列化规范消息结构

Redis发布订阅不校验消息类型,业务需自行约定序列化协议 简单来说,Redis的发布订阅(Pub Sub)机制本身,对消息内容是完全“无感”的。它就像一个只管搬运、不管验货的传送带。这意味着,消息类型的定义、校验和解析,完全落在了业务开发者的肩上。在Spring Boot这类框架中,如果使用不当,

时间:2026-04-24 22:04
SQL如何计算分组内的方差与标准差_窗口聚合函数实操

SQL如何计算分组内的方差与标准差_窗口聚合函数实操

SQL中VARIANCE和STDDEV默认按样本计算(除以n-1),PostgreSQL、Oracle、Snowflake均如此;MySQL的VARIANCE()等价VAR_SAMP(),STDDEV()等价STDDEV_SAMP();SQL Server需显式用STDEV()或STDEVP()。

时间:2026-04-24 22:04
为什么SQL触发器在执行存储过程时不触发_排查触发器嵌套触发限制

为什么SQL触发器在执行存储过程时不触发_排查触发器嵌套触发限制

为什么SQL触发器在执行存储过程时不触发?排查触发器嵌套触发限制 触发器调用存储过程后不触发,根本不是“不触发”,而是被嵌套层数限制拦住了 很多开发者遇到触发器“失灵”时,第一反应是检查语法或权限。但真相往往更直接:你很可能撞上了SQL Server那堵硬性的32层嵌套墙。无论是DML还是DDL触发

时间:2026-04-24 22:04
mysql如何高效地统计不同状态的数量_使用CountIf单次扫描

mysql如何高效地统计不同状态的数量_使用CountIf单次扫描

MySQL不支持COUNTIF函数,需用SUM(CASE WHEN THEN 1 ELSE 0 END)实现单次扫描多状态统计,比多次COUNT(*)更高效。 MySQL 没有 COUNTIF 函数,别白找 如果你是从Excel或者其他数据库(比如SQLite、PostgreSQL)转过来的,可

时间:2026-04-24 22:04
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜
热门教程
更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程