У меня есть следующий код, который дает мне ошибку:
Message: Invalid parameter number: number of bound variables does not match number of tokens
Код:
public function getCount($ids, $outcome) { if (!is_array($ids)) { $ids = array($ids); } $qb = $this->getEntityManager()->createQueryBuilder(); $qb->add('select', $qb->expr()->count('r.id')) ->add('from', '\My\Entity\Rating r'); if ($outcome === 'wins') { $qb->add('where', $qb->expr()->in('r.winner', array('?1'))); } if ($outcome === 'fails') { $qb->add('where', $qb->expr()->in('r.loser', array('?1'))); } $qb->setParameter(1, $ids); $query = $qb->getQuery(); //die('q = ' . $qb); return $query->getSingleScalarResult(); }
Данные (или $ ids):
Array ( [0] => 566 [1] => 569 [2] => 571 )
Результат DQL:
q = SELECT COUNT(r.id) FROM \My\Entity\Rating r WHERE r.winner IN('?1')
Изучая эту проблему, я нашел то, что будет важно для всех, кто работает в этой же проблеме и ищет решение.
Из исходного сообщения следующая строка кода:
$qb->add('where', $qb->expr()->in('r.winner', array('?1')));
Приобретение именованного параметра в качестве массива вызывает проблему с номером связанного параметра. Удалив его из упаковки массива:
$qb->add('where', $qb->expr()->in('r.winner', '?1'));
Эта проблема должна быть исправлена. Возможно, это была проблема в предыдущих версиях Doctrine, но она исправлена в самых последних версиях версии 2.0.
Самый простой способ сделать это – связать сам массив как параметр:
$queryBuilder->andWhere('r.winner IN (:ids)') ->setParameter('ids', $ids);
и для завершения строкового решения
$qb->andWhere('foo.field IN (:string)'); $qb->setParameter('string', array('foo', 'bar'), \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);
Я обнаружил, что, несмотря на то, что указывают документы, единственный способ заставить это работать:
$ids = array(...); // Array of your values $qb->add('where', $qb->expr()->in('r.winner', $ids));
http://groups.google.com/group/doctrine-dev/browse_thread/thread/fbf70837293676fb
Лучший способ сделать это – особенно если вы добавляете более одного условия – это:
$values = array(...); // array of your values $qb->andWhere('where', $qb->expr()->in('r.winner', $values));
Если ваш массив значений содержит строки, вы не можете использовать метод setParameter со впалой строкой, потому что ваши кавычки будут экранированы!
Вот как я его использовал:
->where('b.status IN (:statuses)') ->setParameters([ 'customerId' => $customerId, 'storeId' => $storeId, 'statuses' => [Status::OPEN, Status::AWAITING_APPROVAL, Status::APPROVED] ]);
Нашел, как это сделать в 2016 году: https://redbeardtechnologies.wordpress.com/2011/07/01/doctrine-2-dql-in-statement/
Цитата:
Вот как это сделать правильно:
$em->createQuery(“SELECT users FROM Entities\User users WHERE users.id IN (:userids)”) ->setParameters(array('userids' => $userIds));
Параметр SetParameters примет массив и соответствующим образом развяжет его для использования в инструкции «IN».
Я знаю, что пример OP использует DQL и построитель запросов, но я наткнулся на это, ища, как это сделать с контроллера или вне класса репозитория, так что, возможно, это поможет другим.
Вы также можете сделать WHERE IN
от контроллера таким образом:
// Symfony example $ids = [1, 2, 3, 4]; $repo = $this->getDoctrine()->getRepository('AppBundle:RepoName'); $result = $repo->findBy([ 'id' => $ids ]);
Я предпочитаю:
$qb->andWhere($qb->expr()->in('t.user_role_id', [ User::USER_ROLE_ID_ADVERTISER, User::USER_ROLE_ID_MANAGER, ]));
->where($qb->expr()->in('foo.bar', ':data')) ->setParameter('participants', $data);
Также работает с:
->andWhere($qb->expr()->in('foo.bar', ':users')) ->setParameter('data', $data);
Я боролся с тем же самым сценарием, когда мне приходилось делать запрос против массива значений.
Следующие работали для меня:
->andWhereIn("[fieldname]", [array[]])
Пример данных массива (работает со строками и целыми числами):
$ids = array(1, 2, 3, 4);
Пример запроса (адаптируйте туда, где он вам нужен):
$q = dataTable::getInstance() ->createQuery() ->where("name = ?",'John') ->andWhereIn("image_id", $ids) ->orderBy('date_created ASC') ->limit(100); $q->execute();