Я пытаюсь и не могу перевести свой относительно простой оператор SQL в тот, который будет работать в Doctrine.
Это оператор SQL, который работает по мере необходимости при работе с моей базой данных:
SELECT a.* FROM score a INNER JOIN ( SELECT name, MAX(score) AS highest FROM score GROUP BY name ) b ON a.score = b.highest AND a.name = b.name GROUP BY name ORDER BY b.highest DESC, a.dateCreated DESC
Вот попытка DQL:
$kb = $em->createQuery( "SELECT a FROM ShmupBundle:Score a INNER JOIN a.name ShmupBundle:Score b WITH a.score = b.score AND a.name = b.name GROUP BY b.name WHERE a.platform='keyboard' GROUP BY a.name ORDER BY b.score DESC, a.dateCreated DESC" );
Что в настоящее время дает эту ошибку:
[Semantical Error] line 0, col 73 near 'ShmupBundle:Score': Error: Class ShmupBundle\Entity\Score has no association named name
Сама таблица довольно проста: id, name, score, platform, dateCreated
Есть несколько записей с тем же именем, но разные баллы. Я хочу показать только «высокую оценку» за каждое имя. Я пробовал в течение дня или двух, без везения. Может кто-то указать мне верное направление?
Запрос, который вы пытаетесь сделать с доктриной, связан с наибольшей-n-на-группой . Чтобы использовать вспомогательный запрос, а затем присоединиться к основному запросу, вам сложно справиться с доктриной. Ниже приведена перезаписанная версия SQL для получения тех же результатов без использования каких-либо агрегатных функций
SELECT a.* FROM score a LEFT JOIN score b ON a.name = b.name AND a.score < b.score WHERE b.score IS NULL ORDER BY a.score DESC
DEMO
Для преобразования вышеуказанного запроса, эквивалентного доктрине или DQL, легко, ниже приведена версия DQL выше SQL
SELECT a FROM AppBundle\Entity\Score a LEFT JOIN AppBundle\Entity\Score b WITH a.name = b.name AND a.score < b.score WHERE b.score IS NULL ORDER BY a.score DESC
Или с построителем запросов вы можете написать что-то вроде того, что я тестировал ниже с помощью symfony 2.8, используя схему DEMO
$DM = $this->get( 'Doctrine' )->getManager(); $repo = $DM->getRepository( 'AppBundle\Entity\Score' ); $results = $repo->createQueryBuilder( 'a' ) ->select( 'a' ) ->leftJoin( 'AppBundle\Entity\Score', 'b', 'WITH', 'a.name = b.name AND a.score < b.score' ) ->where( 'b.score IS NULL' ) ->orderBy( 'a.score','DESC' ) ->getQuery() ->getResult();
Другая идея – создать представление, используя ваш запрос в базе данных, а в symfony создать объект, который помещает имя представления в аннотацию таблицы и только начинать вызывать вашу сущность, он даст результаты, возвращенные вашим запросом, но этот подход не рекомендуется просто временное исправление ,
Inner Join Statement требует первого аргумента в виде таблицы, то есть семантической ошибки в вашем запросе.
$kb = $em->createQuery( "SELECT a FROM ShmupBundle:Score a INNER JOIN ShmupBundle:Score b ON a.score = b.score AND a.name = b.name GROUP BY b.name WHERE a.platform='keyboard' GROUP BY a.name ORDER BY b.score DESC, a.dateCreated DESC");
:
Если ShmupBundle:Score
должен быть базой и таблицей, тогда используйте .
, Если Доктрина должна что-то заменить, то что с ней делать? GROUP BY
, и оно должно быть после WHERE
. Попробуйте удалить GROUP BY b.name
. GROUP BY
и b.name
и a.name
так как они равны. использовать это в классе
$name = $em->getRepository('AppBundle:BlogPost')->getMaxId();
в репозитории вы можете использовать что-то вроде
public function getMaxId() { $qb = $this->createQueryBuilder('u'); $qb->select('u, MAX(id) as idMax'); return $qb->getQuery()->getSingleResult(); }