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

Symfony6+Doctrine中createQueryBuilder分组排序结果异常求助

解决Symfony 6 + Doctrine中按分组获取最新记录的问题

你的问题核心在于:当前写法里的GROUP BY和ORDER BY执行逻辑不符合预期。关闭ONLY_FULL_GROUP_BY后,MySQL会返回每组的第一条匹配记录,但ORDER BY fth.date DESC是对分组后的结果集排序,而非分组内部排序,所以无法拿到每个formation_niveau对应的最新有效记录。

方案一:子查询关联(兼容所有数据库版本)

先通过子查询获取每个formation_niveau的最大有效日期,再关联主表查询对应完整记录:

public function enCours(): array
{
    // 子查询:提取每个FormationNiveau的最新有效日期(<=当前日期)
    $subQuery = $this->createQueryBuilder('fth_sub')
        ->select('fth_sub.FormationNiveau, MAX(fth_sub.date) AS max_date')
        ->where('fth_sub.date <= :ddj')
        ->groupBy('fth_sub.FormationNiveau')
        ->getDQL();

    return $this->createQueryBuilder('fth')
        ->innerJoin(
            sprintf('(%s)', $subQuery),
            'sub',
            'WITH',
            'fth.FormationNiveau = sub.FormationNiveau AND fth.date = sub.max_date'
        )
        ->setParameter('ddj', new \DateTime()) // 用DateTime对象更规范,Doctrine自动处理格式
        ->getQuery()
        ->getResult();
}

方案二:窗口函数(推荐,需数据库支持)

如果你的数据库是MySQL 8.0+、PostgreSQL 9.4+等支持窗口函数的版本,可以用ROW_NUMBER()直接在分组内排序,取每组第一条:

public function enCours(): array
{
    $dql = <<<DQL
        SELECT fth
        FROM App\Entity\FormationTauxHoraire fth
        WHERE fth.date <= :ddj
        AND (
            ROW_NUMBER() OVER (
                PARTITION BY fth.FormationNiveau 
                ORDER BY fth.date DESC
            )
        ) = 1
    DQL;

    return $this->getEntityManager()
        ->createQuery($dql)
        ->setParameter('ddj', new \DateTime())
        ->getResult();
}

注意事项

  • 避免用date('Y-m-d')传递日期参数,改用\DateTime对象,Doctrine会自动适配数据库的日期格式,同时规避时区问题
  • 关闭ONLY_FULL_GROUP_BY属于临时 workaround,不符合SQL标准,容易引发不可预期的结果,建议用上述标准写法替代

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 05:42:49