Doctrine查询语言获取每组最大/最新行数

时间:2017-09-07 23:41:14

标签: php mysql symfony doctrine greatest-n-per-group

我正在尝试并且未能将我相对简单的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

有多个条目具有相同的名称,但分数不同。我想只显示每个名字的“高分”。我一直在尝试一两天,没有运气。有人能指出我正确的方向吗?

4 个答案:

答案 0 :(得分:8)

您尝试使用doctrine的查询与相关。要使用子查询然后与主查询连接,要使用doctrine来处理复杂的事情。所以下面是重写的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

要将上述查询转换为等同于doctrine或DQL很容易,下面是上面SQL的DQL版本:

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

或者使用查询构建器,您可以使用DEMO Schema

编写类似我在下面使用symfony 2.8测试的内容
$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中创建一个实体将视图名称放在表注释中,然后开始调用您的实体,它将给出查询返回的结果,但不推荐这种方法暂时解决。

答案 1 :(得分:2)

Inner Join语句需要第一个参数作为表,这是查询中的语义错误。

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

答案 2 :(得分:2)

使用它 在课堂上

 $name = $em->getRepository('AppBundle:BlogPost')->getMaxId();

在存储库中,您可以使用类似

的内容
 public function getMaxId()
{
$qb = $this->createQueryBuilder('u');
$qb->select('u, MAX(id) as idMax');  
return $qb->getQuery()->getSingleResult();
}

答案 3 :(得分:0)

  • MySQL不理解:语法。如果ShmupBundle:Score应该是数据库和表,那么使用.。如果Doctrine应该用某些东西代替它,那么它用它做什么呢?
  • 只能有一个GROUP BY子句,它必须是之后的<{em} WHERE子句。请尝试删除GROUP BY b.name
  • GROUP BYb.name都不需要a.name,因为它们是平等的。