【问题标题】:Doctrine Update query with a sub-query带有子查询的教义更新查询
【发布时间】:2011-07-21 16:39:17
【问题描述】:

我正在尝试使用教义 dql 执行类似于以下查询的查询:

Doctrine_Query::create()
              ->update('Table a')
              ->set('a.amount',
                    '(SELECT sum(b.amount) FROM Table b WHERE b.client_id = a.id AND b.regular = ? AND b.finished = ?)',
                    array(false, false))
              ->execute();

但它会引发 Doctrine_Query_Exception 并显示消息:“未知组件别名 b”

在'set'子句中使用子查询有限制吗,你能给我一些帮助吗?

提前致谢。

【问题讨论】:

  • 您确定要更新表中的所有行吗?这种更新查询可能会导致amount 列中的数据不同,具体取决于用于更新的顺序。 (我假设ab 是同一个表的别名。这是正确的还是它们是两个不同的表?)
  • 嗨@ypercube,没有 a 和 b 是不同表的别名。表 a 用于客户,表 b 用于其帐户。

标签: php mysql symfony1 doctrine dql


【解决方案1】:

几年后,但可能会有所帮助。

是的]

如果您需要/想要/必须,您可以使用 Querybuilder 来执行具有 sub select 语句的 update 查询,而不是直接使用底层连接层.
这里的想法是使用 QueryBuilder 两次。

  • 构建一个选择语句来计算新值。
  • 构建实际更新查询以提交到数据库,您将在其中注入以前的 select DQL,正如您所期望的那样,以发出单个数据库请求。

示例]

给定一个用户可以出售物品的应用程序。每笔交易都涉及买方和卖方。交易结束后,卖家和买家可以对交易如何与对方进行评论。
您可能需要一个User表、一个Review表和一个Transaction表。
User 表包含一个名为 rating 的字段,它将保存用户的平均评分。 Review 表存储一个事务 id、作者 id(提交评论的人)、一个值(从 0 到 5)。最后,交易包含买卖双方的参考。

现在假设您想在对方提交评论后更新用户的平均评分。更新查询将计算用户的平均评分并将结果作为User.rating 属性的值。
我将以下 sn-p 与 Doctrine 2.5Symfony3 一起使用。由于这项工作是关于用户的,我在 AppBundle\Entity\UserRepository.php 存储库中创建一个名为 updateRating( User $user) 的新公共函数是有意义的。

/**
 * Update the average rating for a user
 * @param User $user The user entity object target
 */
public function updateRating( User $user )
{
    // Compute Subrequest. The reference table being Transaction, we get its repository first.
    $transactionRepo = $this->_em->getRepository('AppBundle:Transaction');
    $tqb = $postRepo->createQueryBuilder('t');
    #1 Computing select
    $select = $tqb->select('SUM(r.value)/count(r.value)')
        // My Review table as no association declared inside annotation (because I do not need it elsewhere)
        // So I need to specify the glue part in order join the two tables
        ->leftJoin('AppBundle:Review','r', Expr\Join::WITH, 'r.post = p.id AND r.author <> :author')
        // In case you have an association declared inside the Transaction entity schema, simply replace the above leftJoin with something like
        // ->leftJoin(t.reviews, 'r')
        // Specify index first (Transaction has been declared as terminated)
        ->where( $tqb->expr()->eq('t.ended', ':ended') )
        // The user can be seller or buyer
        ->andWhere( $tqb->expr()->orX(
            $tqb->expr()->eq('t.seller', ':author'),
            $tqb->expr()->eq('t.buyer', ':author')
        ));
    #2 The actual update query, containing the above sub-request
    $update = $this->createQueryBuilder('u')
        // We want to update a row
        ->update()
        // Setting the new value using the above sub-request
        ->set('u.rating', '('. $select->getQuery()->getDQL() .')')
        // should apply to the user we want
        ->where('u.id = :author')
        // Set parameters for both the main & sub queries
        ->setParameters([ 'ended' => 1, 'author' => $user->getId() ]);
    // Get the update success status
    return $update->getQuery()->getSingleScalarResult();
}

现在来自控制器

            // … Update User's rating
            $em->getRepository('AppBundle:User')->updateRating($member);
            // …

【讨论】:

    【解决方案2】:

    我不确定这是否有限制,但我记得前一段时间曾与此作斗争。我最终得到了它:

    $q = Doctrine_Manager::getInstance()->getCurrentConnection();
    $q->execute("UPDATE table a SET a.amount = (SELECT SUM(b.amount) FROM table b WHERE b.client_id = a.id AND b.regular = 0 AND b.finished = 0)");
    

    看看这是否能解决问题。请注意,此查询不会执行自动变量转义,因为它不是 DQL。

    【讨论】:

    • 是的,成功了。我在发布问题几分钟后找到了这个解决方案。无论如何,这对我来说是一个解决方案,谢谢
    猜你喜欢
    • 1970-01-01
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多