鉴于此实体
class SystemRecord
{
/**
* @ORM\Id
* @ORM\Column(type="integer", name="ID")
* @ORM\GeneratedValue
* @var int
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Application\Entity\User")
* @ORM\JoinColumn(name="USER_SERIAL", referencedColumnName="SERIAL", nullable=false)
* @var User
*/
private $user;
/**
* @ORM\Column(type="utcdatetime", name="DATE_DATA_WAS_FETCHED", nullable=false)
* @var DateTimeInterface
*/
private $dateDataWasFetched;
}
...和这个dql
$dql = "
select r
from Application\\Entity\\SystemRecord r
join Application\\Entity\\User u
where r.dateDataWasFetched = (
select max(r2.dateDataWasFetched)
from Application\\Entity\\SystemRecord r2
)
and u.serial = :serial
";
$query = $this->getEntityManager()->createQuery($dql);
$query->setParameter('serial', $user->getSerial());
$sql = $query->getSql();
...我希望得到具有指定序列号的用户的SystemRecords,但只有那些具有最新日期的SystemRecord"。换句话说,在程序上,"为任何用户找到任何SystemRecord的最新日期。然后查找在该日期发生的指定用户的记录。"
如果我正在写sql,我会写
select *
from SYSTEM_RECORDS r
join USER u
on r.USER_SERIAL = u.SERIAL
where DATE_DATA_WAS_FETCHED = (select max(DATE_DATA_WAS_FETCHED) from SYSTEM_RECORDS)
and u.SERIAL = ?
但是,教义给了我以下的sql
SELECT ...fields from s0_ ...
FROM SYSTEM_RECORDS s0_
INNER
JOIN
USER u1_
ON (s0_.DATE_DATA_WAS_FETCHED = (SELECT max(s2_.DATE_DATA_WAS_FETCHED) AS dctrn__1
FROM SYSTEM_RECORDS s2_) AND u1_.SERIAL = ?)
这不是我想要的。对于SystemRecords与具有指定序列号的用户的最新SystemRecords具有相同日期的所有用户,这给了我" SystemRecords。
如何使用dql制作查询?
答案 0 :(得分:2)
如果我理解正确,你需要像你一样使用子查询,但我认为你错过了in
表达式。使用QueryBuilder
,您可以构建查询以获得此结果(我总是使用QueryBuilder
编写查询):
$qb->select(r)
->from('SystemRecord', 'r')
->join('r.user', 'u')
->where(
$qb->expr()->in(
'r.dateDataWasFetched',
"SELECT max(r2.dateDataWasFetched) FROM Application\\Entity\\SystemRecord r2"
)
)
->andWhere('u.serial' = :user_serial)
->setParameter('user_serial', $user->getSerial())
->getQuery()
->getResult();
此答案基于this answer to similar question on stackoverflow。
如果您真的想要DQL
,那么在使用QueryBuilder
方法构建查询之后,您可以轻松地从getDQL
实例中获取它:
$dql = $qb->getQuery()->getDQL();
答案 1 :(得分:1)
我能够通过避免加入来解决/避免我的问题
$dql = "
select r
from Application\\Entity\\SystemRecord r
where r.dateDataWasFetched = (
select max(r2.dateDataWasFetched)
from Application\\Entity\\SystemRecord r2
)
and r.user = :user
";
$query = $this->getEntityManager()->createQuery($dql);
$query->setParameter('user', $user);
产生的sql(正确)
SELECT ...fields from s0_ ...
FROM SYSTEM_RECORDS s0_
WHERE s0_.DATE_DATA_WAS_FETCHED = (SELECT max(s1_.DATE_DATA_WAS_FETCHED) AS dctrn__1
FROM SYSTEM_RECORDS s1_) AND s0_.USER_SERIAL = ?
值得注意的是,我不是指定关联实体的ID(通过u.serial = :serial
,而是指定实体本身(通过r.user = :user
)。这样我就可以省略也加入。顺便说一下 - serial
字段在@ORM\Id
实体中标有User
。
然而,这只是避免了这个问题。我仍然感到困惑的是,当存在联接时,教条如何解释查询。
感谢Wilt,在使用查询构建器然后使用getDQL()方法后,我发现了缺少的细节。工作的dql是
select r
from Application\Entity\SystemRecord r
join r.user u
where r.dateDataWasFetched = (
select max(r2.dateDataWasFetched)
from Application\\Entity\\SystemRecord r2
)
and u.serial = :serial
请注意,我原始问题中的DQL与此工作解决方案之间的差异分别为join Application\\Entity\\User u
vs join r.user u
。