简体   繁体   English

Doctrine JOIN 与 DQL 中的子查询

[英]Doctrine JOIN with subquery in DQL

I have this SQL:我有这个 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

and when I tried to convert it to DQL当我尝试将其转换为 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);

I'm getting:我越来越:

[Semantical Error] line 0, col 452 near 'JOIN (SELECT\r\n ': Error: Subquery is not supported here

Using QueryBuilder is same..使用 QueryBuilder 是一样的..

Is there any hack to use left join with subquery either in DQL or using QueryBuilder?在 DQL 或使用 QueryBuilder 中使用左连接和子查询有什么技巧吗?

Thank you谢谢

As answered in #3542正如#3542中的回答

DQL is about querying objects. DQL 是关于查询对象的。 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).在 FROM 子句中支持子选择意味着 DQL 解析器无法再构建结果集映射(因为子查询返回的字段可能不再匹配 object)。

Your best bet would be to use sql instead您最好的选择是改用 sql

$conn = $this->getEntityManager()->getConnection();
$sql = 'Your query';
$stmt = $conn->prepare($sql);
$stmt->execute(); //Bind what parameters you need

I don't think that you will need a sub query for this when you can handle it with join and aggregation.当您可以使用连接和聚合处理它时,我认为您不需要子查询。 Like in the main query join your contact entity and perform aggregation for your desired result set.就像在主查询中加入您的contact实体并为您想要的结果集执行聚合一样。 I have updated the group by clause and added all non aggregated columns that are in select clause so that this query will be valid even if mysql's strict mode is enabled see MySQL Handling of GROUP BY and it will eliminate duplicate rows also as per the grouping criteria我已经更新了 group by 子句并添加了 select 子句中的所有非聚合列,这样即使启用了 mysql 的严格模式,此查询也将有效,请参阅MySQL 处理 GROUP BY ,它还将根据分组标准消除重复行

In SQL it will be like在 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

I believe you will need to add an extension to support Mysql's GROUP_CONCAT function in doctrine by default this not included in doctrine orm. I believe you will need to add an extension to support Mysql's GROUP_CONCAT function in doctrine by default this not included in doctrine orm.

To add support for GROUP_CONCAT in doctrine you can follow the steps mentioned in linked answer.在 doctrine 中添加对 GROUP_CONCAT 的支持,您可以按照链接答案中提到的步骤进行操作。 Once its registered you can transform your raw SQL to DQL as注册后,您可以将原始 SQL 转换为 DQL

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
    

Or another approach will be to use ResultSetMapping class of doctrine in which you can execute your raw SQL and map the result on the respective entities Or another approach will be to use ResultSetMapping class of doctrine in which you can execute your raw SQL and map the result on the respective entities

$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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM