Doctrine генерирует неправильный SQL при объединении агрегатных полей (сгруппировать по) и упорядочения (с упорядочением по) в запросе с помощью Paginator - PullRequest
0 голосов
/ 04 марта 2019

У меня есть простые двунаправленные отношения один-ко-многим между Item и Valoracion (обзор).Следующий запрос должен получить среднюю оценку и количество отзывов для каждого элемента в порядке убывания:

$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Выражение № 5 списка SELECT отсутствует в предложении 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() все работает нормально.Я все еще прошу помощи, поскольку Twig , по-видимому, использует getIterator() за циклом for, когда $pag передается в шаблон.
  • Если пункты ORDER BY удалены,все тоже отлично работает!
  • Я использую MySQL 5.7.25, sql_mode=ONLY_FULL_GROUP_BY и не хочу его менять.

1 Ответ

0 голосов
/ 04 марта 2019

В этом случае вы не выбираете объединенную коллекцию «to-many», вы группируете по Item id и просто агрегируете значения отношения « valoraciones ».

Согласно документации по нумерации доктрин , в этом случае вы можете отключить флаг $ fetchJoinCollection :

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

ItКажется, проблема вызвана доктриной, пытающейся добавить «пропущенные поля» из порядка по условию в предложение select. Связанная проблема Запрос на извлечение

В этом случае он считает, что должен добавить «v.score» к выбору.

В качестве альтернативы, вы могли быотключите использование выходных ходунков в paginator, чтобы избежать описанного выше поведения:

$pag->setUseOutputWalkers(false);
...