sql_mode=only_full_group_by导致GROUP BY查询报错及分组需求问询
解决MySQL GROUP BY与only_full_group_by模式冲突的问题
这个问题我之前踩过坑!MySQL的only_full_group_by严格模式会强制要求:SELECT列表中的所有非聚合列必须出现在GROUP BY子句中,否则就会抛出你遇到的那个错误。你的需求是每个唯一weight对应一条记录,下面给你几种靠谱的解决思路:
方法1:使用聚合函数指定要返回的组内记录
如果你的需求是取每组中id最小(或最大)的那条记录,可以用MIN()/MAX()聚合函数锁定id,再关联原表获取对应的name:
SELECT r.id, r.name, r.weight FROM resource r JOIN ( SELECT MIN(id) AS min_id, weight FROM resource JOIN inventory ON resource.weight = inventory.weight WHERE inventory.key = ? GROUP BY weight ) AS grouped ON r.id = grouped.min_id;
这个写法先通过子查询按weight分组,拿到每组的最小id,再关联原表获取对应的name和weight,结果完全可控。
方法2:用窗口函数灵活选择组内记录(推荐)
如果你需要更灵活的规则(比如按id排序取第一条/最后一条,或者按其他字段排序),窗口函数ROW_NUMBER()是最优解:
WITH ranked_resources AS ( SELECT resource.id, resource.name, resource.weight, -- 按weight分组,每组内按id升序编号(取第一条),如果要取最后一条改成ORDER BY id DESC ROW_NUMBER() OVER (PARTITION BY resource.weight ORDER BY resource.id ASC) AS rn FROM resource JOIN inventory ON resource.weight = inventory.weight WHERE inventory.key = ? ) SELECT id, name, weight FROM ranked_resources WHERE rn = 1;
PARTITION BY resource.weight:把数据按weight拆分成独立的组ROW_NUMBER() OVER (...):给每组内的行按指定规则编号- 最后筛选
rn=1的行,就是每组的第一条记录
方法3:临时关闭only_full_group_by模式(不推荐)
虽然可以临时关闭这个严格模式,但非常不建议——这会违反SQL标准,返回的id和name是随机的,结果不可控:
-- 临时关闭当前会话的only_full_group_by模式 SET sql_mode = (SELECT REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', '')); -- 再执行你的原查询(结果可能随机) SELECT resource.id, resource.name, resource.weight FROM resource JOIN inventory ON resource.weight = inventory.weight WHERE inventory.key = ? GROUP BY resource.weight;
这种方法只适合临时测试,生产环境绝对不要用!
内容的提问来源于stack exchange,提问作者Garuuk
相关产品推荐
相关产品推荐

