You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

MySQL中如何选择GROUP BY以外的其他列?附数据表结构示例

在MySQL中执行GROUP BY时如何选择分组字段以外的其他列?

嘿,针对你的问题(还有你给出的那张包含idorg_entry_idcheck_incheck_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对应的最新签到记录的idcheck_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会随机返回分组内某一行的字段值,结果完全不可控,很容易导致业务逻辑错误。

操作步骤如下:

  1. 先查看当前SQL模式:
SELECT @@sql_mode;
  1. 临时关闭ONLY_FULL_GROUP_BY(重启MySQL后会恢复默认设置):
SET sql_mode = REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY', '');
  1. 之后就可以直接写这样的查询(但结果不可靠):
SELECT org_entry_id, id, check_in
FROM your_table_name
GROUP BY org_entry_id;

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

火山引擎 最新活动