DQL 中带有子查询的 Doctrine JOIN
Doctrine JOIN with subquery in DQL
我有这个 SQL:
SELECT
s.id,
e.exception,
s.name,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.name as partner,
p.id as partnerId,
group_concat(c.name) names,
group_concat(c.email) emails,
group_concat(c.tel) tels
FROM
service s
JOIN web w ON s.web_id = w.id
JOIN rus r ON w.rus_id = r.id
JOIN partner p ON r.partner_id = p.id
LEFT JOIN exception e ON e.service_id = s.id
JOIN contact c ON c.partner_id = c.id
where c.main = 1 or c.important = 1
group by s.id
当我尝试将其转换为 DQL 时
$result = $this->_em
->createQuery(
'SELECT s.name, w.webId, r.email, p.name as PartnerName
FROM App\Model\Database\Entity\Service s
JOIN App\Model\Database\Entity\Web w WITH s.web = w.id
JOIN App\Model\Database\Entity\Rus r WITH w.rus = r.id
JOIN App\Model\Database\Entity\Partner p WITH r.partner = p.id
LEFT JOIN App\Model\Database\Entity\Exception e WITH e.service = s.id
LEFT JOIN (SELECT
p.id,
group_concat(c.name) names,
group_concat(c.tel) tels,
group_concat(c.email) emails
FROM
App\Model\Database\Entity\Partner p
LEFT JOIN App\Model\Database\Entity\Contact c WITH c.partner = p.id
where c.main = 1 or c.important = 1
group by p.id) test
WHERE test.id = p.id'
)->getResult();
return new ArrayCollection($result);
我得到:
[Semantical Error] line 0, col 452 near 'JOIN (SELECT\r\n ': Error: Subquery is not supported here
使用 QueryBuilder 是一样的..
在 DQL 中或使用 QueryBuilder 中,是否有任何 hack 可以将左连接与子查询一起使用?
谢谢
中的回答
DQL is about querying objects. Supporting subselects in the FROM
clause means that the DQL parser is not able to build the result set
mapping anymore (as the fields returned by the subquery may not match
the object anymore).
您最好的选择是使用 sql 而不是
$conn = $this->getEntityManager()->getConnection();
$sql = 'Your query';
$stmt = $conn->prepare($sql);
$stmt->execute(); //Bind what parameters you need
当您可以使用连接和聚合处理时,我认为您不需要子查询。就像在主查询中一样,加入您的 contact
实体并为您想要的结果集执行聚合。我已经更新了 group by 子句并添加了 select 子句中的所有非聚合列,这样即使启用了 mysql 的严格模式,该查询也将有效,请参阅 MySQL Handling of GROUP BY 和它也将根据分组标准消除重复行
在SQL会像
SELECT
s.id,
s.name,
e.exception,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.name as partnerName,
p.id as partnerId,
group_concat(c.name) names,
group_concat(c.email) emails,
group_concat(c.tel) tels
FROM service s
left join exception e ON e.service_id = s.id
join web w ON s.web_id = w.id
join rus r ON w.rus_id = r.id
join partner p ON r.partner_id = p.id
join contact c ON c.partner_id = c.id
WHERE c.main = 1 or c.important = 1
GROUP BY s.id,
s.name,
e.exception,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.name,
p.id
我相信你需要添加一个扩展来支持 Mysql 的 GROUP_CONCAT 学说默认功能,这不包含在学说 orm 中。
要添加对 GROUP_CONCAT in doctrine 的支持,您可以按照链接答案中提到的步骤进行操作。注册后,您可以将原始 SQL 转换为 DQL as
SELECT s.id,
s.name,
e.exception,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.id as partnerId,
p.name as partnerName,
GROUP_CONCAT(c.name) contactNames,
GROUP_CONCAT(c.email) contactEmails,
GROUP_CONCAT(c.tel) contactTels
FROM App\Model\Database\Entity\Service s
LEFT JOIN App\Model\Database\Entity\Exception e WITH e.service = s.id
JOIN App\Model\Database\Entity\Web w WITH s.web = w.id
JOIN App\Model\Database\Entity\Rus r WITH w.rus = r.id
JOIN App\Model\Database\Entity\Partner p WITH r.partner = p.id
JOIN App\Model\Database\Entity\Contact c WITH c.partner = p.id
WHERE c.main = 1 or c.important = 1
GROUP BY s.id,
s.name,
e.exception,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.name,
p.id
或者另一种方法是使用 ResultSetMapping
class 的学说,您可以在其中执行原始 SQL 并将结果映射到各个实体
$rsm = new ResultSetMapping;
$rsm->addEntityResult('App\Model\Database\Entity\Service', 's');
$rsm->addFieldResult('s', 'id', 'id');
$rsm->addFieldResult('s', 'name', 'name');
$rsm->addJoinedEntityResult('App\Model\Database\Entity\Exception' , 'e', 's', 'exception');
$rsm->addFieldResult('e', 'exception', 'exception');
//.... other relations
$rsm->addJoinedEntityResult('App\Model\Database\Entity\Partner' , 'p', 'r', 'partner');
$rsm->addFieldResult('p', 'partnerName', 'name');
$rsm->addScalarResult('contactNames', 'contactNames');
// ... and so on
$sql = 'SELECT s.id, e.exception ... FROM service s JOIN ... WHERE ... GROUP BY s.id, e.exception ...';
$query = $this->_em->createNativeQuery($sql, $rsm);
$data = $query->getResult();
我有这个 SQL:
SELECT
s.id,
e.exception,
s.name,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.name as partner,
p.id as partnerId,
group_concat(c.name) names,
group_concat(c.email) emails,
group_concat(c.tel) tels
FROM
service s
JOIN web w ON s.web_id = w.id
JOIN rus r ON w.rus_id = r.id
JOIN partner p ON r.partner_id = p.id
LEFT JOIN exception e ON e.service_id = s.id
JOIN contact c ON c.partner_id = c.id
where c.main = 1 or c.important = 1
group by s.id
当我尝试将其转换为 DQL 时
$result = $this->_em
->createQuery(
'SELECT s.name, w.webId, r.email, p.name as PartnerName
FROM App\Model\Database\Entity\Service s
JOIN App\Model\Database\Entity\Web w WITH s.web = w.id
JOIN App\Model\Database\Entity\Rus r WITH w.rus = r.id
JOIN App\Model\Database\Entity\Partner p WITH r.partner = p.id
LEFT JOIN App\Model\Database\Entity\Exception e WITH e.service = s.id
LEFT JOIN (SELECT
p.id,
group_concat(c.name) names,
group_concat(c.tel) tels,
group_concat(c.email) emails
FROM
App\Model\Database\Entity\Partner p
LEFT JOIN App\Model\Database\Entity\Contact c WITH c.partner = p.id
where c.main = 1 or c.important = 1
group by p.id) test
WHERE test.id = p.id'
)->getResult();
return new ArrayCollection($result);
我得到:
[Semantical Error] line 0, col 452 near 'JOIN (SELECT\r\n ': Error: Subquery is not supported here
使用 QueryBuilder 是一样的..
在 DQL 中或使用 QueryBuilder 中,是否有任何 hack 可以将左连接与子查询一起使用?
谢谢
DQL is about querying objects. Supporting subselects in the FROM clause means that the DQL parser is not able to build the result set mapping anymore (as the fields returned by the subquery may not match the object anymore).
您最好的选择是使用 sql 而不是
$conn = $this->getEntityManager()->getConnection();
$sql = 'Your query';
$stmt = $conn->prepare($sql);
$stmt->execute(); //Bind what parameters you need
当您可以使用连接和聚合处理时,我认为您不需要子查询。就像在主查询中一样,加入您的 contact
实体并为您想要的结果集执行聚合。我已经更新了 group by 子句并添加了 select 子句中的所有非聚合列,这样即使启用了 mysql 的严格模式,该查询也将有效,请参阅 MySQL Handling of GROUP BY 和它也将根据分组标准消除重复行
在SQL会像
SELECT
s.id,
s.name,
e.exception,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.name as partnerName,
p.id as partnerId,
group_concat(c.name) names,
group_concat(c.email) emails,
group_concat(c.tel) tels
FROM service s
left join exception e ON e.service_id = s.id
join web w ON s.web_id = w.id
join rus r ON w.rus_id = r.id
join partner p ON r.partner_id = p.id
join contact c ON c.partner_id = c.id
WHERE c.main = 1 or c.important = 1
GROUP BY s.id,
s.name,
e.exception,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.name,
p.id
我相信你需要添加一个扩展来支持 Mysql 的 GROUP_CONCAT 学说默认功能,这不包含在学说 orm 中。
要添加对 GROUP_CONCAT in doctrine 的支持,您可以按照链接答案中提到的步骤进行操作。注册后,您可以将原始 SQL 转换为 DQL as
SELECT s.id,
s.name,
e.exception,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.id as partnerId,
p.name as partnerName,
GROUP_CONCAT(c.name) contactNames,
GROUP_CONCAT(c.email) contactEmails,
GROUP_CONCAT(c.tel) contactTels
FROM App\Model\Database\Entity\Service s
LEFT JOIN App\Model\Database\Entity\Exception e WITH e.service = s.id
JOIN App\Model\Database\Entity\Web w WITH s.web = w.id
JOIN App\Model\Database\Entity\Rus r WITH w.rus = r.id
JOIN App\Model\Database\Entity\Partner p WITH r.partner = p.id
JOIN App\Model\Database\Entity\Contact c WITH c.partner = p.id
WHERE c.main = 1 or c.important = 1
GROUP BY s.id,
s.name,
e.exception,
w.url,
w.web_id,
w.active,
w.suspended,
r.email,
p.name,
p.id
或者另一种方法是使用 ResultSetMapping
class 的学说,您可以在其中执行原始 SQL 并将结果映射到各个实体
$rsm = new ResultSetMapping;
$rsm->addEntityResult('App\Model\Database\Entity\Service', 's');
$rsm->addFieldResult('s', 'id', 'id');
$rsm->addFieldResult('s', 'name', 'name');
$rsm->addJoinedEntityResult('App\Model\Database\Entity\Exception' , 'e', 's', 'exception');
$rsm->addFieldResult('e', 'exception', 'exception');
//.... other relations
$rsm->addJoinedEntityResult('App\Model\Database\Entity\Partner' , 'p', 'r', 'partner');
$rsm->addFieldResult('p', 'partnerName', 'name');
$rsm->addScalarResult('contactNames', 'contactNames');
// ... and so on
$sql = 'SELECT s.id, e.exception ... FROM service s JOIN ... WHERE ... GROUP BY s.id, e.exception ...';
$query = $this->_em->createNativeQuery($sql, $rsm);
$data = $query->getResult();