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

Symfony查询兼容sql_mode ONLY_FULL_GROUP_BY遇ANY_VALUE识别错误

解决思路

方法一:注册Doctrine自定义DQL函数(推荐)

Doctrine ORM默认不识别MySQL的ANY_VALUE()函数,需手动注册让Doctrine能解析它:

  1. 创建自定义函数类
    在项目中新建类文件src/Doctrine/Function/AnyValue.php,代码如下:
<?php

namespace App\Doctrine\Function;

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;

class AnyValue extends FunctionNode
{
    public $expression = null;

    public function parse(Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->expression = $parser->SingleValuedPathExpression();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

    public function getSql(SqlWalker $sqlWalker)
    {
        return 'ANY_VALUE(' . $this->expression->dispatch($sqlWalker) . ')';
    }
}
  1. 配置Doctrine识别该函数
    在Symfony的Doctrine配置文件(如config/packages/doctrine.yaml)中添加DQL函数配置:
doctrine:
    orm:
        dql:
            string_functions:
                ANY_VALUE: App\Doctrine\Function\AnyValue
  1. 修改QueryBuilder查询
    将select中不属于聚合、也不在GROUP BY的字段用ANY_VALUE()包裹,示例:
return $this->createQueryBuilder('m')
    ->select('m.id, m.tutor, m.allow_tester, m.title, ANY_VALUE(g.title) as groupTitle, ANY_VALUE(gc.color) as color, COUNT(ms.id) as length')
    ->leftJoin('m.group_modules', 'gm')
    ->leftJoin('gm.module_group', 'g')
    ->leftJoin('g.programs', 'p')
    ->leftJoin('g.color', 'gc')
    ->leftJoin('m.steps', 'ms')
    ->where('p = :p')
    ->setParameter('p', $program)
    ->groupBy('m.id')
    ->orderBy('gm.sorting', 'ASC')
    ->orderBy('g.id', 'ASC')
    ->getQuery()
    ->getResult();

方法二:扩展GROUP BY子句(适合字段值唯一场景)

如果每个m.id对应的g.title、gc.color等字段值是唯一的(即一个模块仅属于一个分组),可以把这些字段全部加入GROUP BY,符合ONLY_FULL_GROUP_BY要求:

return $this->createQueryBuilder('m')
    ->select('m.id, m.tutor, m.allow_tester, m.title, g.title as groupTitle, gc.color, COUNT(ms.id) as length')
    ->leftJoin('m.group_modules', 'gm')
    ->leftJoin('gm.module_group', 'g')
    ->leftJoin('g.programs', 'p')
    ->leftJoin('g.color', 'gc')
    ->leftJoin('m.steps', 'ms')
    ->where('p = :p')
    ->setParameter('p', $program)
    ->groupBy('m.id, m.tutor, m.allow_tester, m.title, g.title, gc.color')
    ->orderBy('gm.sorting', 'ASC')
    ->orderBy('g.id', 'ASC')
    ->getQuery()
    ->getResult();

注意:若存在一个模块对应多个分组的情况,该方法会拆分分组结果,不符合原业务逻辑,不建议使用。

方法三:使用原生SQL查询

绕过Doctrine DQL,直接编写原生MySQL语句,可直接使用ANY_VALUE()函数:

$em = $this->getEntityManager();
$sql = "
    SELECT m.id, m.tutor, m.allow_tester, m.title, ANY_VALUE(g.title) as groupTitle, ANY_VALUE(gc.color) as color, COUNT(ms.id) as length
    FROM module m
    LEFT JOIN group_modules gm ON m.id = gm.module_id
    LEFT JOIN module_group g ON gm.module_group_id = g.id
    LEFT JOIN program_module_group pmg ON g.id = pmg.module_group_id
    LEFT JOIN program p ON pmg.program_id = p.id
    LEFT JOIN color gc ON g.color_id = gc.id
    LEFT JOIN module_step ms ON m.id = ms.module_id
    WHERE p.id = :p
    GROUP BY m.id
    ORDER BY gm.sorting ASC, g.id ASC
";
$query = $em->createNativeQuery($sql, $this->createResultSetMappingBuilder('m'));
$query->setParameter('p', $program);
return $query->getResult();

注意:需根据你的实体类名和数据库表名,调整SQL中的表名与关联字段,ResultSetMappingBuilder会自动将结果映射到实体对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 01:24:31