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.name
。
GROUP BY
不需要 b.name
和 a.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 个必须实现的抽象方法