DQL Выберите все строки, имеющие значение MAX одного столбца

Работая с Symfony 2 и Doctrine, я ищу способ выбрать все строки, имеющие максимальное значение в определенном столбце.

Прямо сейчас я делаю это в двух запросах:

  • Один, чтобы получить максимальное значение столбца в таблице
  • Затем я выбираю строки, имеющие это значение.

Я уверен, что это можно сделать одним запросом.

В поисках я нашел этот ответ в Тема, кажется, это то, что я ищу, но в SQL.

Итак, согласно первому решению ответа, запрос, который я пытаюсь построить, будет выглядеть примерно так:

select yt.id, yt.rev, yt.contents
from YourTable yt
inner join(
select id, max(rev) rev
from YourTable
group by id
) ss on yt.id = ss.id and yt.rev = ss.rev

Кто-нибудь знает, как это сделать в Doctrine DQL?

На данный момент вот код для моих тестов (не работает):

$qb2= $this->createQueryBuilder('ms')
->select('ms, MAX(m.periodeComptable) maxPeriode')
->where('ms.affaire = :affaire')
->setParameter('affaire', $affaire);

$qb = $this->createQueryBuilder('m')
->select('m')
//->where('m.periodeComptable = maxPeriode')

// This is what I thought was the most logical way of doing it:
->innerJoin('GAAffairesBundle:MontantMarche mm, MAX(mm.periodeComptable) maxPeriode', 'mm', 'WITH', 'm.periodeComptable = mm.maxPeriode')

// This is a version trying with another query ($qb2) as subquery, which would be the better way of doing it for me,
// as I am already using this subquery elsewhere
//->innerJoin($qb2->getDQL(), 'sub', 'WITH', 'm.periodeComptable = sub.maxPeriode')

// Another weird try mixing DQL and SQL logic :/
//->innerJoin('SELECT MontantMarche mm, MAX(mm.periodeComptable) maxPeriode ON m.periodeComptable = mm.maxPeriode', 'sub')

//->groupBy('m')
->andWhere('m.affaire = :affaire')
->setParameter('affaire', $affaire);

return $qb->getQuery()->getResult();

Entity — GAAffairesBundle: MontantMarche, поэтому этот код находится в методе соответствующего репозитория.

В более общем плане я учусь тому, как обрабатывать подзапросы (SQL & DQL) и синтаксис DQL для сложных запросов.

Спасибо!

4

Решение

После нескольких часов головной боли, поисков в Google и показаний stackOverflow …
Я наконец узнал, как это сделать.

Вот мой последний код DQL queryBuilder:

    $qb = $this->createQueryBuilder('a');
$qb2= $this->createQueryBuilder('mss')
->select('MAX(mss.periodeComptable) maxPeriode')
->where('mss.affaire = a')
;

$qb ->innerJoin('GAAffairesBundle:MontantMarche', 'm', 'WITH', $qb->expr()->eq( 'm.periodeComptable', '('.$qb2->getDQL().')' ))
->where('a = :affaire')
->setParameter('affaire', $affaire)
;

return $qb->getQuery()->getResult();
4

Другие решения

Для меня, когда я пытаюсь сделать подзапрос, я делаю:

->andWhere($qb->expr()->eq('affaire', $qb2->getDql()));
0

Чтобы достичь этого, используя чистый DQL и без использования какой-либо агрегатной функции, вы можете написать доктрину как

SELECT a
FROM GAAffairesBundle:MontantMarche a
LEFT JOIN GAAffairesBundle:MontantMarche b
WITH a.affaire = b.affaire
AND a.periodeComptable < b.periodeComptable
WHERE b.affaire IS NULL
ORDER BY a.periodeComptable DESC

Вышеприведенное вернет вам максимальную запись на группу affaire)

Expalnation

Эквивалентный SQL для вышеупомянутого DQL будет похож

SELECT a.*
FROM MontantMarche a
LEFT JOIN MontantMarche b
ON a.affaire = b.affaire
AND a.periodeComptable < b.periodeComptable
WHERE b.affaire IS NULL
ORDER BY a.periodeComptable DESC

Здесь я предполагаю, что может быть несколько записей в таблице, например, (MontantMarche) для каждого affaireтак что здесь я пытаюсь сделать сам присоединиться к affaire и еще один трюк в соединении, я пытаюсь объединить только строки из правой таблицы(b) где Период < b’s periodeComptable, поэтому строка для левой таблицы (a) с самым высоким periodeComptable будет иметь нулевую строку из правой таблицы(b) таким образом, чтобы выбрать самый высокий ряд за affaire WHERE right table row IS NULL необходимо.

Точно так же используя ваш отправленный пример запроса с внутренним объединением можно записать как

select yt.id, yt.rev, yt.contents
from YourTable yt
left join YourTable ss on yt.id = ss.id and yt.rev < ss.rev
where ss.rev is null

Надеюсь, это имеет смысл

0
По вопросам рекламы [email protected]