复杂查询与学说结合
Complex query join with doctrine
我正在构建一个查询以向用户显示项目,然后显示该项目的最高出价。
示例:
詹姆斯的 Xbox 360。 - 最高出价为 55 美元。
马里奥的艺术 table。 - 最高出价为 25 美元。
查询
SELECT i, u
FROM AppBundle:Item i
LEFT JOIN i.user u
我还有另一个 table 出价(一对多关系)。我不确定如何在使用 join 的同一查询中包含该项目的单个最高出价。
我知道我可以 运行 在此查询之后使用函数(关系)进行另一个查询,但出于优化原因我避免这样做。
解决方案
SQL
- 但是这在 DQL 学说中怎么可能呢?
您的 SQL 查询可能类似于
select i,u
from i
inner join bids u on i.id = u.item_id
WHERE
i.value = (select max(value) from bids where item_id = i.id)
group by i
DQL,我认为它不支持子查询,因此您可以尝试使用 Having
子句或查看 Doctrine\ORM\Query\Expr
是否提供任何内容。
为了针对我自己的情况解决这个问题,我使用 Doctrine 的 Collections' Criteria
向原始实体(项目)添加了一个方法来查找实体列表(出价)中的最大实体写了关于它 here.
您的 Item
实体将包含
public function getMaxBid()
{
$criteria = Criteria::create();
$criteria->orderBy(['bid.value' => Criteria::ASC]);
$criteria->setLimit(1);
return $this->bids->matching($criteria);
}
不幸的是,i 无法通过一次分组查询找到最高出价 和 出价者,但是有几种技术使逻辑适用于多个查询。您可以做一个 sub select,这可能会正常工作,具体取决于 table 的大小。如果您计划增长到无法正常工作的地步,您可能已经在考虑共享您的关系数据库,将一些数据移动到事务较少、性能更高的数据库技术,或者非规范化,但如果您想要保持此实现为纯 MySQL,您可以使用一个过程在多个命令中表达如何检查出价并有选择地添加到列表中,还可以在非规范化高出价 table 中更新当前高出价者.这将如何验证出价的复杂逻辑保留在一个管理最严格的地方——数据库。只需确保您正确使用交易来阻止同时记录 2 个出价(例如,SELECT FOR UPDATE)。
我曾经让未来的程序员写这个查询,看看他们对 MySQL 的经验如何,许多人认为只需要最大分组就足够了,还有一些人离开面试时仍然相信它会工作得很好i 错了。好问题!
在这种情况下,您可以将 IN
与子查询一起使用。
我不确定我是否正确理解了你的模型,但我试图用 QueryBuilder
进行查询,我相信你会设法让它与这个例子一起工作:
$qb = $this->_em->createQueryBuilder();
$sub = $qb;
$sub->select('mbi') // max bid item
->where('i.id = mbi.id')
->leftJoin('mbi.bids', 'b'))
->andWhere($qb->expr()->max('b.value'))
->getQuery();
$qb = $qb->select('i', 'u')
->where($qb->expr()->in('i', $sub->getDQL()))
->leftJoin('i.user', 'u');
$query = $qb->getQuery();
return $query->getResult();
我正在构建一个查询以向用户显示项目,然后显示该项目的最高出价。
示例:
詹姆斯的 Xbox 360。 - 最高出价为 55 美元。
马里奥的艺术 table。 - 最高出价为 25 美元。
查询
SELECT i, u
FROM AppBundle:Item i
LEFT JOIN i.user u
我还有另一个 table 出价(一对多关系)。我不确定如何在使用 join 的同一查询中包含该项目的单个最高出价。
我知道我可以 运行 在此查询之后使用函数(关系)进行另一个查询,但出于优化原因我避免这样做。
解决方案
SQL - 但是这在 DQL 学说中怎么可能呢?
您的 SQL 查询可能类似于
select i,u
from i
inner join bids u on i.id = u.item_id
WHERE
i.value = (select max(value) from bids where item_id = i.id)
group by i
DQL,我认为它不支持子查询,因此您可以尝试使用 Having
子句或查看 Doctrine\ORM\Query\Expr
是否提供任何内容。
为了针对我自己的情况解决这个问题,我使用 Doctrine 的 Collections' Criteria
向原始实体(项目)添加了一个方法来查找实体列表(出价)中的最大实体写了关于它 here.
您的 Item
实体将包含
public function getMaxBid()
{
$criteria = Criteria::create();
$criteria->orderBy(['bid.value' => Criteria::ASC]);
$criteria->setLimit(1);
return $this->bids->matching($criteria);
}
不幸的是,i 无法通过一次分组查询找到最高出价 和 出价者,但是有几种技术使逻辑适用于多个查询。您可以做一个 sub select,这可能会正常工作,具体取决于 table 的大小。如果您计划增长到无法正常工作的地步,您可能已经在考虑共享您的关系数据库,将一些数据移动到事务较少、性能更高的数据库技术,或者非规范化,但如果您想要保持此实现为纯 MySQL,您可以使用一个过程在多个命令中表达如何检查出价并有选择地添加到列表中,还可以在非规范化高出价 table 中更新当前高出价者.这将如何验证出价的复杂逻辑保留在一个管理最严格的地方——数据库。只需确保您正确使用交易来阻止同时记录 2 个出价(例如,SELECT FOR UPDATE)。
我曾经让未来的程序员写这个查询,看看他们对 MySQL 的经验如何,许多人认为只需要最大分组就足够了,还有一些人离开面试时仍然相信它会工作得很好i 错了。好问题!
在这种情况下,您可以将 IN
与子查询一起使用。
我不确定我是否正确理解了你的模型,但我试图用 QueryBuilder
进行查询,我相信你会设法让它与这个例子一起工作:
$qb = $this->_em->createQueryBuilder();
$sub = $qb;
$sub->select('mbi') // max bid item
->where('i.id = mbi.id')
->leftJoin('mbi.bids', 'b'))
->andWhere($qb->expr()->max('b.value'))
->getQuery();
$qb = $qb->select('i', 'u')
->where($qb->expr()->in('i', $sub->getDQL()))
->leftJoin('i.user', 'u');
$query = $qb->getQuery();
return $query->getResult();