MySQL开启only_full_group_by时如何获取GROUP BY语句的单个值
only_full_group_by模式下获取每个公司任意客户ID的问题 嘿,这个问题我太熟悉了!咱们先搞清楚为啥你原来的SQL会报错:
Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column customer.id which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
这个错误的核心是only_full_group_by模式的严格要求:SELECT列表里的列要么出现在GROUP BY子句中,要么被聚合函数(比如SUM、MIN)处理。你原来的SQL里id既不在GROUP BY里,也没被聚合,MySQL自然就抛出错误了。
不过完全不用关闭这个模式(毕竟它能帮你规避很多逻辑漏洞),下面给你三种靠谱的解决方案:
方案1:用聚合函数取最小/最大ID
如果你不介意取每个公司对应的最小或最大客户ID,这是最简单的方法,完全符合only_full_group_by的规则:
SELECT company_id, MIN(id) AS customer_id FROM `customer` WHERE company_id IS NOT NULL GROUP BY `company_id`;
也可以把MIN(id)换成MAX(id),效果类似,都是每个公司返回一个确定的客户ID。
方案2:用窗口函数灵活选取任意ID
如果你想更灵活(比如真的随机取任意一个,或者按其他规则选第一个),可以用ROW_NUMBER()窗口函数:
SELECT company_id, id AS customer_id FROM ( SELECT company_id, id, -- 按company_id分组,给每组的行编号,ORDER BY可换成RAND()实现随机选取 ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY id) AS row_num FROM `customer` WHERE company_id IS NOT NULL ) AS sub_query WHERE row_num = 1;
把ORDER BY id改成ORDER BY RAND(),就能每次随机获取每个公司的一个客户ID,自由度很高。
方案3:用ANY_VALUE()函数直接取任意值
MySQL 8.0及以上版本提供了ANY_VALUE()函数,专门用来处理这种“我明确要取任意一个值”的场景,它会告诉MySQL:这个列我知道不满足函数依赖,直接返回该分组里的任意一个值就行。写法最贴近你原来的SQL:
SELECT company_id, ANY_VALUE(id) AS customer_id FROM `customer` WHERE company_id IS NOT NULL GROUP BY `company_id`;
这个方法最省事,几乎不用改动原SQL的结构,给id加个ANY_VALUE()包裹就搞定了。
内容的提问来源于stack exchange,提问作者Atma

