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

У меня есть простая двунаправленная связь «один ко многим» между 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]: 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? Я делаю что-то неправильно?

Примечания:

  • Если использовать getQuery()->getResult() вместо getIterator(), все работает нормально. Я все еще прошу помощи, так как Twig по-видимому использует getIterator() за циклом for, когда $pag передается в шаблон.
  • Если удалить пункты ORDER BY, тоже все работает нормально!
  • Я использую MySQL 5.7.25, sql_mode=ONLY_FULL_GROUP_BY и НЕ хочу его менять.
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
4
0
529
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В этом случае вы не выбираете объединенную коллекцию «ко многим», вы группируете по Идентификатор элемента и просто агрегируете значения отношения «валорасионес».

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

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

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

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

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

$pag->setUseOutputWalkers(false);

Инициализация пагинатора с помощью $fetchJoinCollection = false сделала свое дело! Теперь итератор работает отлично.

Rafael Aquino 07.03.2019 13:45

В качестве примечания: в Twig, по-видимому, при повторении результата getQuery()->getResult(), хотя он содержит текущие элементы страницы, переменные loop будут содержать неожиданные значения; loop.length выдаст общее количество элементов вместо количества элементов для текущей страницы; и loop.last не будет истинным для последнего элемента коллекции, а не для последнего элемента страницы.

Rafael Aquino 07.03.2019 13:58

Спасибо! Упомянутая вами проблема говорит о том, что она должна быть исправлена ​​в 2.7, но ошибка все еще здесь.

StockBreak 12.06.2020 09:28

Другие вопросы по теме