You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL:如何在SELECT结果中保留首条记录并移除后续重复项

解决GROUP BY无法按排序保留每组首条记录的问题

嘿,太懂这种纠结了!GROUP BY在MySQL(尤其是旧版本)里的行为确实有点“任性”——它不会遵循你写的外部ORDER BY来选择组内的记录,因为SQL的执行顺序里,GROUP BY是在ORDER BY之前运行的,你最后加的排序只是对最终分组后的结果做排序,根本影响不到分组时选哪条记录当组内代表。

下面给你两种靠谱的解决方案,能精准控制保留每组的首条记录:

方法一:窗口函数ROW_NUMBER()(推荐,适合MySQL 8.0+)

这是现代数据库最标准、易维护的方案,核心思路是先给每组重复记录按你想要的顺序编号,然后只留编号为1的那条。

假设你的表是test,按name字段判断重复,想要按id降序保留每组第一条,代码如下:

WITH ranked_records AS (
  SELECT 
    id,
    name,
    -- 按重复字段分组,组内按指定规则排序并编号,第一条就是1
    ROW_NUMBER() OVER (PARTITION BY name ORDER BY id DESC) AS row_num
  FROM test
)
SELECT id, name
FROM ranked_records
WHERE row_num = 1;

关键细节:

  • PARTITION BY name:把数据按你认为“重复”的字段分成组(如果是多个字段重复,就写PARTITION BY col1, col2)
  • ORDER BY id DESC:定义每组内的排序规则,决定哪条记录会被标为row_num=1(改成ASC就能保留组内id最小的那条)
  • 最后筛选row_num=1,就能得到每组的首条记录

方法二:关联子查询(兼容MySQL 5.x等旧版本)

如果你的数据库不支持窗口函数,可以用关联子查询实现相同效果:

SELECT t1.id, t1.name
FROM test t1
WHERE t1.id = (
  -- 子查询找到当前name组内按指定排序的第一条id
  SELECT t2.id
  FROM test t2
  WHERE t2.name = t1.name
  ORDER BY t2.id DESC
  LIMIT 1
);

这个逻辑很直白:主查询每条记录,都会通过子查询找到同组内符合排序规则的第一条记录的id,只有当当前记录的id等于这个id时才保留,完美实现每组只留首条。

为啥之前的GROUP BY不行?

你遇到的问题本质是:

  • 在MySQL的非严格SQL模式下,GROUP BY会从每组中随机选择一条记录(你那个例子里一直选id=1可能是因为存储引擎的物理存储顺序,但这绝对不是可靠的行为)
  • 你写的ORDER BY id DESC是在GROUP BY执行完之后才运行的,它只是把分组后的结果排序,根本改变不了分组时选的是哪条记录

内容的提问来源于stack exchange,提问作者Pavel K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:51:30