【问题标题】:Doctrine JOIN with subquery in DQLDoctrine JOIN 与 DQL 中的子查询
【发布时间】:2021-08-05 14:28:37
【问题描述】:

我有这个 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 中使用左连接和子查询有什么技巧吗?

谢谢

【问题讨论】:

    标签: php doctrine-orm doctrine


    【解决方案1】:

    正如#3542中的回答

    DQL 是关于查询对象的。支持 FROM 中的子选择 子句表示 DQL 解析器无法构建结果集 不再映射(因为子查询返回的字段可能不匹配 对象了)。

    最好的办法是使用 sql

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

    【讨论】:

    • 是的,我尝试使用原始 SQL,但它迫使我重写已经为 QueryBuilder 准备好的大块。我接下来要考虑的是创建视图并加入它。但我不是确定教义中的观点..
    • 视图可能是个好主意。您是否已经看过并尝试过这个:robbert.rocks/…
    【解决方案2】:

    当您可以使用连接和聚合处理它时,我认为您不需要子查询。就像在主查询中一样,加入您的 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

    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 学说类,您可以在其中执行原始 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();
    

    【讨论】:

    • 哦,我解决的方法和你 4 天前描述的一样。无论如何都会给你赏金:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    • 2017-03-02
    • 2016-05-03
    • 1970-01-01
    相关资源
    最近更新 更多