Working with Symfony 2 and Doctrine, I\'m searching for a way to select every rows having the max value in a specific column.
Right now, I\'m doing it in two queries
For me when i trying to make a subquery i make:
->andWhere($qb->expr()->eq('affaire', $qb2->getDql()));
After some hours of headache and googling and stackOverflow readings... I finally found out how to make it.
Here is my final DQL queryBuilder code:
$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();
To achieve this using pure DQL and without use of any aggregate function you can write doctrine query as
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
The above will return you max record per group (per affaire
)
Expalnation
The equivalent SQL for above DQL will be like
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
Here i assume there can be multiple entries in table e.g(MontantMarche) for each affaire
, so here i am trying to do a self join on affaire
and another tweak in join is i am trying to join only rows from right table(b)
where a's periodeComptable < b's periodeComptable, So the row for left table (a)
with highest periodeComptable
will have a null row from right table(b)
thus to pick the highest row per affaire
the WHERE right table row IS NULL
necessary.
Similarly using your posted sample query with inner join can be written as
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
Hope it makes sense