Doctrine Update query с подзапросом - PullRequest
0 голосов
/ 21 июля 2011

Я пытаюсь выполнить запрос, подобный следующему, используя 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();

Но он вызывает исключение Doctrine_Query_Exception с сообщением: "Неизвестный псевдоним компонента b"

Есть ли ограничения на использование подзапросов в предложении 'set', можете ли вы мне помочь?

Заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 29 ноября 2016

Спустя годы, но может помочь.

Да]

Если вам нужно / хотите / нужно, вы можете использовать Querybuilder для выполнения запроса на обновление , имеющего оператор sub select, вместо непосредственного использования нижележащего уровня соединения.
Идея в том, чтобы использовать QueryBuilder дважды.

  • Построение оператора select для вычисления нового значения.
  • Создайте фактический запрос на обновление для отправки в базу данных, в которой вы будете вводить первый выбранный DQL, как вы и ожидали, для выдачи одного запроса к базе данных.

Пример]

Предоставлено приложение, в котором пользователи могут продавать объекты. Каждая сделка включает в себя покупателя и продавца. После завершения транзакции продавцы и покупатели могут оставить отзыв о том, как прошла сделка с их контрагентом.
Вам может потребоваться таблица Пользователь , таблица Просмотр и таблица Транзакция .
Таблица User содержит поле с именем rating , в котором будет храниться средний рейтинг пользователя. В таблице Review хранится идентификатор транзакции, идентификатор автора (который отправил обзор), значение (от 0 до 5). Наконец, транзакция содержит ссылку как для продавца, так и для покупателя.

Теперь предположим, что вы хотите обновить средний рейтинг для пользователя после того, как счетчик отправил отзыв. Запрос на обновление вычислит среднюю оценку для пользователя и поместит результат в качестве значения свойства User.rating.
Я использовал следующий фрагмент кода с Doctrine 2.5 и Symfony3 . Поскольку работа касается пользователей, я имею смысл создать новую общедоступную функцию с именем 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();
}

Теперь с контроллера

            // … Update User's rating
            $em->getRepository('AppBundle:User')->updateRating($member);
            // …
1 голос
/ 22 июля 2011

Я не уверен, есть ли ограничения на это, но я помню, как боролся с этим некоторое время назад.В конце концов я начал работать с:

$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.

...