Doctrine Query Language 获取每组的最大/最新行

Posted

技术标签:

【中文标题】Doctrine Query Language 获取每组的最大/最新行【英文标题】:Doctrine Query Language get Max/Latest Row Per Group 【发布时间】:2018-02-16 19:06:16 【问题描述】:

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

有多个条目具有相同的名称,但分数不同。我只想显示每个名称的“高分”。我已经试穿了一两天了,没有运气。谁能指出我正确的方向?

【问题讨论】:

你能分享实体 ShmupBundle:Score 吗? 【参考方案1】:

您尝试对教义进行的查询与greatest-n-per-group 有关。要使用子查询,然后与主查询连接,用学说处理起来会很复杂。所以下面是重写的 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很容易,下面是上面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 中创建一个实体,将视图名称放在表注释中,然后开始调用您的实体,它将给出您的查询返回的结果,但不推荐这种方法只是临时修复。

【讨论】:

这很好用,谢谢。我有一种感觉,有一种更简单的方法可以解决这个问题,我拼凑的 SQL 查询是一个多年未使用 php 的人试图让它工作的结果。【参考方案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");

【讨论】:

这给了我一个错误:“[Syntax Error] line 0, col 90: Error: Expected Doctrine\ORM\Query\Lexer::T_WITH, got 'ON'”。然后我尝试将 ON 更改为 WITH,它返回“预期的字符串结尾,得到 'WHERE'”。 不,我不熟悉如何使用这种语法进行内部连接。 非常简单。看看这个docs.doctrine-project.org/projects/doctrine-dbal/en/latest/… 对不起,我真的一点也不轻松。几天来,我一直用头撞墙,但无济于事。我所做的一切似乎都不起作用。 :(【参考方案3】: mysql 不理解: 语法。如果ShmupBundle:Score 应该是数据库和表,则使用.。如果 Doctrine 应该用什么来代替它,那么它用它做什么? GROUP BY 子句只能有一个,并且必须在WHERE 子句之后。尝试删除GROUP BY b.nameGROUP BY 不需要 b.namea.name,因为它们是相等的。

【讨论】:

ShmupBundle:Score 符号有时会在 Symfony 项目中使用。【参考方案4】:

使用这个 在课堂上

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

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

 public function getMaxId()

$qb = $this->createQueryBuilder('u');
$qb->select('u, MAX(id) as idMax');  
return $qb->getQuery()->getSingleResult();

每个实体都带有一些我们定义或未定义的默认存储库功能 如果我们希望添加一些额外的功能,我们会在存储库类中写下自定义函数。就像我想再添加一个函数 getMaxId 我将在存储库中写下以访问此函数。

为了从每个组中获取最大值或最小值,我们可以使用给定的查询进行操作

select * from (select * from mytable order by `Group`, age desc, Person) x group by `Group

这不是从每个组中获取最大值的好方法,因为我们需要为此写下子查询。 除此之外我们还有 Row_number() 函数

 SELECT sd.* FROM ( SELECT sale_person_id,sale_person_name,no_products_sold,commission_percentage,sales_department,ROW_NUMBER() OVER(PARTITION BY sale_person_id ORDER BY no_products_sold DESC) rowNumber FROM sales_department_details  )sd  WHERE sd.rowNumber =1;

here you find out all work arounds

【讨论】:

请在您的回答中添加一些解释,以便其他人可以从您的回答中学习。此方法如何按名称对分数进行分组?

以上是关于Doctrine Query Language 获取每组的最大/最新行的主要内容,如果未能解决你的问题,请参考以下文章

Symfony 和 Doctrine 1.2.2:如何获取 Doctrine_Query 对象的 SQL 子句?

KnpPaginatorBundle - 致命错误:Doctrine\ORM\Query\AsIsHydrator 包含 1 个必须实现的抽象方法

Doctrine Query Builder 使用数组

sql查询不适用于doctrine 2

Doctrine Query Builder,“介于”表达式和子查询之间

Doctrine Query builder,计算相关的一对多行