在使用Paginator的查询中组合聚合字段(分组依据)和排序(排序依据)时,Doctrine会生成错误的SQL

问题描述 投票:2回答:1

我在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]:语法错误或访问冲突:1055 SELECT列表的表达式#5不在GROUP BY子句中,并且包含非聚合列'test.v1_.score',它在功能上不依赖于GROUP BY子句中的列;这与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呢?难道我做错了什么?

笔记:

  • 如果使用getQuery()->getResult()而不是getIterator()一切正常。我仍然在寻求帮助,因为当getIterator()传递给模板时,Twig显然在for循环后面使用$pag
  • 如果ORDER BY条款被删除,一切都正常!
  • 我正在使用MySQL 5.7.25,sql_mode=ONLY_FULL_GROUP_BY,我不想改变它。
php mysql doctrine twig doctrine-query
1个回答
1
投票

在这种情况下,您不会获取已连接的“to-many集合”,您可以按Item ID进行分组,只是聚合“valoraciones”关系的值。

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

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

似乎问题是由于学说试图将条件中的“缺失字段”添加到select子句中而引起的。 Related issue Pull request

在这种情况下,它认为它应该向选择添加“v.score”。

或者,您可以禁用分页器中输出walker的使用以避免上述行为:

$pag->setUseOutputWalkers(false);
© www.soinside.com 2019 - 2024. All rights reserved.