在使用分页器的查询中组合聚合字段(group by)和排序(order by)时,Doctrine 生成不正确的 SQL

Doctrine generates incorrect SQL when combining aggregate fields (group by) and ordering (order by) in a query with Paginator

我在 ItemValoracion 之间有一个简单的双向一对多关系(评论)。以下查询应按降序获取每个项目的平均分数和评论数:

$itemsQb = $em->getRepository(Item::class)->createQueryBuilder('i')
    ->select('i as data')
    ->addSelect('avg(v.score) as avg_score')
    ->addSelect('count(v.score) as num_reviews')
    ->leftJoin('i.valoraciones', 'v')
    ->groupBy('i.id')
    ->addOrderBy('avg_score', 'DESC')
    ->addOrderBy('num_reviews', 'DESC');

其中 $em 是工作中的 Doctrine\ORM\EntityManager 实例。使用Doctrine\ORM\Tools\Pagination\Paginator对上述查询进行分页并使用getIterator()遍历结果时抛出异常,如下:

$pag = new Paginator($itemsQb);

// first page, up to three results per page
$pag->getQuery()->setFirstResult(0)->setMaxResults(3);

// display results one by one
echo "Name\t\tAvg\tNum\n";
foreach ($pag->getIterator() as $p) {
   echo $p['data']->name . "\t" . $p['avg_score'] . "\t" . $p['num_reviews'] . "\n";
}

SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #5 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.v1_.score' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

生成了以下 SQL 查询

SELECT DISTINCT
id_5
FROM
(SELECT DISTINCT
    id_5, sclr_2, sclr_3
FROM
    (SELECT 
    i0_.id AS id_0,
        i0_.name AS name_1,
        AVG(v1_.score) AS sclr_2,
        COUNT(v1_.score) AS sclr_3,
        v1_.score AS score_4,
        i0_.id AS id_5
FROM
    item i0_
LEFT JOIN valoracion v1_ ON i0_.id = v1_.item_id
GROUP BY i0_.id) dctrn_result_inner
ORDER BY sclr_2 DESC , sclr_3 DESC) dctrn_result
LIMIT 3

很明显 v1_.score AS score_4, 行根本不应该出现!

那么,为什么会生成这个无效的 SQL?我做错了什么吗?

备注:

在这种情况下,您不会获取加入的 "to-many collection",而是按 项目 ID 分组,并且只是聚合“valoraciones 的值"关系。

根据doctrine pagination documentation,在这种情况下,您可以禁用 $fetchJoinCollection 标志:

$pag = new Paginator($itemsQb, false);

这个问题似乎是由试图将 "missing fields" 从按条件排序的 "missing fields" 添加到 select 子句的学说引起的。 Related issue Pull request

在这种情况下,它认为应该将 "v.score" 添加到 select。

或者,您可以在分页器中禁用输出遍历器以避免上述行为:

$pag->setUseOutputWalkers(false);