You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Doctrine DQL自动添加查询字段引发only_full_group_by错误

解决DQL分组查询引发的MySQL 1055错误

嘿,这个问题我太熟悉了!你碰到的SQLSTATE[42000]: 1055错误,根源是MySQL默认开启的ONLY_FULL_GROUP_BY严格模式——它要求SELECT列表里的所有非聚合列必须出现在GROUP BY子句中。

你的DQL语句写的是SELECT p FROM Plan p,这意味着要查询Plan实体的所有字段,但GROUP BY只指定了p.id。MySQL会检查Plan的每一个字段,只要某个字段不在GROUP BY里也没有用聚合函数包裹,就会抛出这个1055错误。

下面给你几个可行的解决方案:

方案1:明确指定字段并同步GROUP BY

如果你不需要Plan的所有字段,只把业务需要的字段列出来,同时把这些字段都加入GROUP BY:

SELECT p.id, p.endsAt, p.organization 
FROM Plan p 
LEFT JOIN p.requests r 
WHERE p.endsAt > :now AND p.organization = :organization 
GROUP BY p.id, p.endsAt, p.organization 
HAVING SUM(CASE WHEN r.isAccepted IS NULL THEN 0 ELSE r.isAccepted END) = 0 
ORDER BY p.id DESC

这种方式完全符合SQL标准,不会有潜在的逻辑问题。

方案2:用聚合函数包裹非主键字段

因为p.id是Plan的主键,每个分组里只会有唯一的Plan记录,所以可以用MAX()或MIN()这类聚合函数包裹其他Plan字段,让MySQL认为这是聚合结果:

SELECT MAX(p) 
FROM Plan p 
LEFT JOIN p.requests r 
WHERE p.endsAt > :now AND p.organization = :organization 
GROUP BY p.id 
HAVING SUM(CASE WHEN r.isAccepted IS NULL THEN 0 ELSE r.isAccepted END) = 0 
ORDER BY p.id DESC

这种写法能直接获取完整的Plan实体,主流ORM(比如Hibernate)都支持这种用法。

方案3:先筛选ID再查询实体

先通过子查询拿到满足分组条件的Plan ID,再用这些ID去查询完整实体,绕开GROUP BY对实体字段的限制:

SELECT p 
FROM Plan p 
WHERE p.id IN (
    SELECT p_inner.id 
    FROM Plan p_inner 
    LEFT JOIN p_inner.requests r_inner 
    WHERE p_inner.endsAt > :now AND p_inner.organization = :organization 
    GROUP BY p_inner.id 
    HAVING SUM(CASE WHEN r_inner.isAccepted IS NULL THEN 0 ELSE r_inner.isAccepted END) = 0
)
AND p.endsAt > :now AND p.organization = :organization 
ORDER BY p.id DESC

这种写法逻辑清晰,分页器遍历也不会报错,适合需要完整实体的场景。

不推荐的方案:关闭ONLY_FULL_GROUP_BY

虽然修改MySQL的sql_mode去掉ONLY_FULL_GROUP_BY能临时解决问题,但这会违反SQL标准,可能导致分组结果出现不可预期的非确定性数据,绝不建议在生产环境使用。

内容的提问来源于stack exchange,提问作者Laurent W.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:17:46