MySQL中如何选择GROUP BY以外的其他列?附数据表结构示例
嘿,针对你的问题(还有你给出的那张包含id、org_entry_id、check_in、check_out字段的表),我来给你梳理下在MySQL里做GROUP BY时怎么正确选择分组外的其他列——这是个挺常见的需求,但稍不注意就会踩坑,尤其是涉及到ONLY_FULL_GROUP_BY模式的影响。
先明确前提:ONLY_FULL_GROUP_BY模式
MySQL默认开启了ONLY_FULL_GROUP_BY SQL模式,这是符合SQL标准的设置:当你使用GROUP BY时,SELECT列表里的字段要么是GROUP BY里的分组字段,要么是被聚合函数处理过的字段。如果直接选非分组、非聚合的字段,会直接报错。所以所有方法都要基于这个前提来操作。
方法1:使用聚合函数(最推荐、最规范)
这是最符合SQL标准的写法,通过聚合函数对分组内的非分组字段做计算,返回明确、可控的结果。比如你想按org_entry_id分组,拿到每个分组最早的签到时间、最晚的签退时间,就可以这么写:
SELECT org_entry_id, MIN(check_in) AS first_check_in, -- 分组内最早的签到时间 MAX(check_out) AS last_check_out, -- 分组内最晚的签退时间 COUNT(id) AS record_count -- 分组内的记录总数 FROM your_table_name GROUP BY org_entry_id;
常用的聚合函数还有AVG()、SUM()、COUNT(DISTINCT ...)等,根据你的业务需求选就行。
方法2:结合子查询获取分组内特定行的完整字段
如果你需要的不是聚合结果,而是分组内某一条特定记录的完整字段(比如每个org_entry_id对应的最新签到记录的id、check_out),可以先通过子查询找到每个分组的标识值(比如最新的check_in时间),再关联原表拿到完整数据:
SELECT t.id, t.org_entry_id, t.check_in, t.check_out FROM your_table_name t INNER JOIN ( -- 先找到每个org_entry_id的最新签到时间 SELECT org_entry_id, MAX(check_in) AS latest_check_in FROM your_table_name GROUP BY org_entry_id ) t2 ON t.org_entry_id = t2.org_entry_id AND t.check_in = t2.latest_check_in;
这种方法的好处是能拿到特定行的所有字段,结果明确,适合需要单条完整记录的场景。
方法3:使用窗口函数(MySQL 8.0+适用)
如果你的MySQL版本是8.0及以上,窗口函数会是更灵活的选择。比如用ROW_NUMBER()给每个分组内的行排序,然后筛选出你需要的那一行:
SELECT id, org_entry_id, check_in, check_out FROM ( SELECT id, org_entry_id, check_in, check_out, -- 按org_entry_id分组,每组内按check_in倒序排,给每行标序号 ROW_NUMBER() OVER (PARTITION BY org_entry_id ORDER BY check_in DESC) AS rn FROM your_table_name ) t WHERE rn = 1; -- 取每组的第一条(也就是最新签到的那条)
窗口函数还支持RANK()、DENSE_RANK()等,适合更复杂的排序筛选需求,写法也比子查询更简洁。
方法4:关闭ONLY_FULL_GROUP_BY(不推荐)
如果你实在想直接SELECT非分组、非聚合的字段,可以临时关闭ONLY_FULL_GROUP_BY模式,但强烈不推荐——因为这样MySQL会随机返回分组内某一行的字段值,结果完全不可控,很容易导致业务逻辑错误。
操作步骤如下:
- 先查看当前SQL模式:
SELECT @@sql_mode;
- 临时关闭ONLY_FULL_GROUP_BY(重启MySQL后会恢复默认设置):
SET sql_mode = REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', '');
- 之后就可以直接写这样的查询(但结果不可靠):
SELECT org_entry_id, id, check_in FROM your_table_name GROUP BY org_entry_id;
内容的提问来源于stack exchange,提问作者Vikas




