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
相关产品推荐
相关产品推荐

