Doctrine Query Language get Max/Latest Row Per Group

10,304

Solution 1

The query you are trying to do with doctrine is related to . To use a sub query and then join with main query get things complicated to handle with doctrine. So below is the rewritten SQL version to get the same results without use of any aggregate functions:

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

To convert above query equivalent to doctrine or DQL is easy, below is the DQL version of above 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

Or with query builder you can write something like i have tested below with symfony 2.8 using the DEMO Schema

$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();

Another idea would be create a view using your query in database and in symfony create an entity put the view name in table annotation and just start calling your entity it will give the results returned by your query but this approach is not recommended just a temporary fix.

Solution 2

Inner Join Statement needs first argument as a table, that is a semantic error in your query.

$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");
Share:
10,304
Douglas
Author by

Douglas

Front End Web Developer

Updated on June 25, 2022

Comments

  • Douglas
    Douglas almost 2 years

    I am trying and failing to translate my relatively simple SQL statement into one that will work within Doctrine.

    This is the SQL statement, which works as required when run against my database:

    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
    

    Here's the DQL attempt thus far:

    $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"
    );
    

    Which is currently giving this error:

    [Semantical Error] line 0, col 73 near 'ShmupBundle:Score': Error: Class ShmupBundle\Entity\Score has no association named name
    

    The table itself is pretty simple: id, name, score, platform, dateCreated

    There are multiple entries with the same name, but different scores. I want to show only the "high score" per name. I've been trying on and off for a day or two now, with no luck. Can anyone point me in the right direction?