Doctrine Query Builder,“介于”表达式和子查询之间
Posted
技术标签:
【中文标题】Doctrine Query Builder,“介于”表达式和子查询之间【英文标题】:Doctrine Query Builder, "between" expression and subquery 【发布时间】:2012-09-26 12:09:06 【问题描述】:我正在尝试使用 Doctrine 的查询构建器创建一个非常复杂的查询(我使用的是 Doctrine 2.2)。在模型中,我有一个 Distributor
类和一个具有一对多关系的 DistributorVisit
类。每次代表访问经销商时,都会在DistributorVisit
表中添加一个带有访问日期的新行。两张表的ER图可以在here找到。
现在我希望能够按他们的上次访问日期过滤经销商。因此,用户输入一个日期范围(上次访问时间和上次访问时间),并列出上次访问日期在这两个日期之间的经销商。我正在使用 Doctrine 的查询生成器,因为我在过滤器中执行了许多其他条件查询,并且我发现面向对象的方法在这种情况下效果最好。这是我在DistributorRepository
课程中所做的:
$qb = $this->getEntityManager()->createQueryBuilder()
->select('o')
->from('MyBundle:Distributor', 'o');
// Lots of 'andWhere's here
$qbv = $this->getEntityManager()->createQueryBuilder();
$qb->andWhere($qb->expr()->between(
$qbv->select($qbv->expr()->max('v.visitDate'))
->from('MyBundle:DistributorVisit', 'v')
->join('MyBundle:Distributor', 'o2',
Join::WITH,
$qbv->expr()->andX(
$qbv->expr()->eq('o2.id', 'v.distributorId'),
$qbv->expr()->eq('o2.id', 'o.id')
))
->getDQL(),
$filter->getLastVisitFrom()->getTimestamp(),
$filter->getLastVisitTo()->getTimestamp()
));
这给了我以下错误:
[Syntax Error] line 0, col 83: Error: Expected Literal, got 'SELECT'
我猜这是因为查询生成器需要一个文字,我的子选择在哪里,但是,子查询的结果应该是文字,对吧?可能是因为查询生成器没有相应地添加括号?
非常感谢您的帮助。
【问题讨论】:
有关如何查看生成的查询的一些详细信息,请参阅这篇文章。从那里开始,如果您还没有弄清楚,请在此处发布查询,以便我们更轻松地为您提供帮助! :-) ***.com/questions/7329288/… 【参考方案1】:我现在通过以下方式解决了这个问题:
$qb = $this->getEntityManager()->createQueryBuilder()
->select('o')
->from('MyBundle:Distributor', 'o');
$qbdv = $this->getEntityManager()->createQueryBuilder();
$qbdv->select('MAX(dv2.visitDate)')
->from('MyBundle:DistributorVisit', 'dv2')
->where($qbdv->expr()->eq('dv2.distributor', 'o'));
$maxVisitDate = '('.$qbdv->getDQL().')';
$qb->leftJoin(
'o.distributorVisits',
'dv',
Join::WITH,
$qb->expr()->eq('dv.visitDate', $maxVisitDate)
);
$qb->andWhere(
$qb->expr()->between(
'dv.visitDate',
':dateFrom',
':dateTo'
)
)
->setParameter('dateFrom', $filter->getLastVisitFrom())
->setParameter('dateTo', $filter->getLastVisitTo());
所以我基本上做了以下事情:我将DistributorVisit
表加入到Distributor
表中,并具有最大访问日期。诀窍在于可以将(子)查询($qb1->getDQL()
)的 DQL 直接传递给 Doctrine 表达式($qb2->expr()->eq('column', $qb1->getDQL()
)。我在上面的代码中使用左连接来做到这一点。
【讨论】:
谢谢,对我很有帮助。【参考方案2】:我猜你当前的 DQL 是这样的:
SELECT ..
FROM ..
WHERE SELECT .. FROM .. BETWEEN .. AND ..
但应该是这样的:
SELECT ..
FROM ..
WHERE (SELECT .. FROM ..) BETWEEN .. AND ..
要修复您的代码,我只需将子查询的 dql 放在括号内:
$subQueryDQL = $qbv->select($qbv->expr()->max('v.visitDate'))
->from('MyBundle:DistributorVisit', 'v')
...
->getDQL();
$qb->andWhere($qb->expr()->between(
sprintf('(%s)', $subQueryDQL),
$filter->getLastVisitFrom()->getTimestamp(),
$filter->getLastVisitTo()->getTimestamp()
));
【讨论】:
我实际上并没有尝试您的解决方案,但它肯定会朝着正确的方向发展。下面你可以看到我是如何实际解决它的,我相信两种解决方案基本上是相等的。【参考方案3】:我的情况:
$qb->andWhere(
"t.field BETWEEN (
$subQuerybuilder1->getDQL()
) AND (
$subQuerybuilder2->getDQL()
)
");
得到:
SELECT ... WHERE t.field BETWEEN (
SELECT t1.field FROM t1
) AND (
SELECT t2.field FROM t2
)
【讨论】:
以上是关于Doctrine Query Builder,“介于”表达式和子查询之间的主要内容,如果未能解决你的问题,请参考以下文章
Doctrine Query Builder,“介于”表达式和子查询之间
Doctrine Query Builder,“between”表达式和子查询
Doctrine Query Builder Select Count with Case
Doctrine DBAL 可以与 ORM Query Builder 混合使用吗?