教义更新查询与子查询

fma*_*iro 0 php mysql doctrine symfony1 dql

我正在尝试使用doctrine 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();
Run Code Online (Sandbox Code Playgroud)

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

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

提前致谢。

Stp*_*ane 5

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

是的

如果需要/想要/必须,可以使用Querybuilder来执行具有子select语句的更新查询,而不是直接使用基础连接层。
这里的想法是两次使用QueryBuilder。

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

范例]

给定一个用户可以在其中出售对象的应用程序。每笔交易都涉及买方和卖方。交易结束后,买卖双方可以与对方交易进行审查。
您可能需要一个User表,一个Review表和一个Transaction表。
“用户”表包含一个名为“ 等级”的字段,该字段将保存用户的平均等级。评论表存储交易ID,作者ID(提交评论的作者),值(0到5)。最后,交易包含卖方和买方的参考。

现在,假设您想在计数器部分提交评论后更新用户的平均评分。更新查询将计算用户的平均评分,并将结果作为User.rating属性的值。
我在Doctrine 2.5Symfony3中使用了以下代码段。由于这项工作是关于用户的,因此我有必要updateRating( User $user)AppBundle \ Entity \ UserRepository.php存储库中创建一个新的公共函数。

/**
 * 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();
}
Run Code Online (Sandbox Code Playgroud)

现在从控制器

            // … Update User's rating
            $em->getRepository('AppBundle:User')->updateRating($member);
            // …
Run Code Online (Sandbox Code Playgroud)