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

时间:2019-03-04 03:26:55

标签: php mysql doctrine twig doctrine-query

我在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,但我不想更改它。

1 个答案:

答案 0 :(得分:0)

在这种情况下,您无需获取已加入的“ to-many collection”,而是按商品ID 分组,而仅汇总“ valoraciones ”关系的值

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

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

问题似乎是由教义试图将按条件排列的“缺失字段”添加到选择子句中引起的。 Related issue Pull request

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

或者,您可以在分页器中禁用输出步进器,以避免出现上述现象:

$pag->setUseOutputWalkers(false);