GROUP BY查询用CONCAT聚合字段触发only_full_group_by错误的解决方法
我有一个简单的invoices表,包含DATE类型的date字段。想要统计每年的发票数量,常规查询如下:
select year(date) year, count(1) num from invoices group by year
但需要直接将结果传入HTML的<select>生成函数,该函数需要键和标签。键为生成的year字段,标签要显示如“2023: 83”这样的内容,于是尝试用CONCAT:
select year(date) year, concat(year(date), ': ', count(1)) label from invoices group by year
但开启了sql_mode=only_full_group_by(我认可严格模式的合理性),MySQL报错:
Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'invoices.date' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
我理解报错原因,但想找更优写法:不想按无意义的label分组,不想用子查询,也不想在查询后处理数据,希望直接从MySQL得到结果。请问聚合查询中能否使用CONCAT?(项目较旧,可能早于only_full_group_by模式)
当然可以在聚合查询中使用CONCAT,只需确保CONCAT内的非聚合字段要么属于GROUP BY子句,要么是聚合函数的结果。以下两种写法都能满足需求:
写法一:引用分组后的字段别名
select year(date) year, concat(year, ': ', count(1)) label from invoices group by year
直接使用已经在GROUP BY中的year别名,符合only_full_group_by的严格要求,同时逻辑完全正确。
写法二:用聚合函数包裹year(date)
select year(date) year, concat(max(year(date)), ': ', count(1)) label from invoices group by year
同一分组内的year(date)结果完全一致,用MAX()(或MIN())包裹不会改变值,但能让MySQL识别该字段是聚合后的结果,满足严格模式的规则。
这两种写法都不需要子查询,也无需在查询后额外处理数据,直接就能得到<select>所需的键和标签格式。
内容的提问来源于stack exchange,提问作者Rudie

