Doctrine 2でWHERE INを使用する方法


124

私にエラーを与える次のコードがあります:

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')

1
私は、これは推奨される方法のだと思いdocs.doctrine-project.org/projects/doctrine-dbal/en/latest/...
マーティン

回答:


114

この問題を調査したところ、この同じ問題が発生し、解決策を探しているすべての人にとって重要なことがわかりました。

元の投稿から、次のコード行:

$qb->add('where', $qb->expr()->in('r.winner', array('?1')));

名前付きパラメーターを配列としてラップすると、バインドされたパラメーター番号の問題が発生します。配列ラッピングから削除することにより:

$qb->add('where', $qb->expr()->in('r.winner', '?1'));

この問題は修正する必要があります。これはDoctrineの以前のバージョンでは問題だったかもしれませんが、2.0の最新バージョンでは修正されています。


5
$qb->expr()->in()はDoctrine 2 ORMにのみ存在し、Doctrine DBALには存在しないと思います。
マーティン2013

3
$qb->expr()->in()確かにDBALにあります
JamesHalsall 2015年

343

これを行う最も簡単な方法は、配列自体をパラメーターとしてバインドすることです。

$queryBuilder->andWhere('r.winner IN (:ids)')
             ->setParameter('ids', $ids);

41
だけでなく、2.1以降
MaciejPyszyński2012

7
@MaciejPyszyński+1。多くの場合、最も簡単な方法は最良の方法です。
AndrzejOśmiałowski14年

2
簡単な説明:これはデフォルトで-> setParameter( 'ids'、$ ids)で機能しますが、-> setParameters( 'ids' => $ ids)では機能しません。デバッグに数分かかりました。
larrydahooster

3
作成するには-> setParameters(...)を使用します ->where('b.status IN (:statuses)') ->setParameters([ 'customerId' => $customerId, 'storeId' => $storeId, 'statuses' => [Status::OPEN, Status::AWAITING_APPROVAL, Status::APPROVED] ]);
ジョージ・ミロナス

5
setParameter強制するために3 Connection::PARAM_STR_ARRAY
番目の

58

そして完成のために文字列ソリューション

$qb->andWhere('foo.field IN (:string)');
$qb->setParameter('string', array('foo', 'bar'), \Doctrine\DBAL\Connection::PARAM_STR_ARRAY);

間違いなく私にとって最良の解決策:-)
Francesco Casula

3
文字列ではなく整数の配列がある場合は、\ Doctrine \ DBAL \ Connection :: PARAM_INT_ARRAYも使用できます。
Omn


12

私はそれが古い投稿であることを知っていますが、誰かに役立つかもしれません。私は投票し、intに関するコメントで尋ねられた質問に対処することによって@Daniel Espendillerの回答を強化します

これをintに対して適切に機能させるには、配列の値がint型であることを確認してください。渡す前にintにキャストを入力できます...

 $qb->andWhere('foo.field IN (:ints)');
 $qb->setParameter('ints', array(1, 2), 
 \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);

symfony 3.4およびdoctrine-bundle:1.8での選択/削除についてテスト済み


8

OPの例がDQLとクエリビルダーを使用していることはわかっていますが、コントローラーまたはリポジトリクラスの外部からそれを行う方法を探していたので、他の人の役に立つかもしれません。

WHERE INこの方法でコントローラからa を実行することもできます:

// Symfony example
$ids    = [1, 2, 3, 4];
$repo   = $this->getDoctrine()->getRepository('AppBundle:RepoName');
$result = $repo->findBy([
    'id' => $ids
]);

1
これは、DQLを使用せずにwhere inを実行するのに完全に受け入れられる方法ですが、彼の質問は彼のDQLコードに関するものでした。彼は単純なだけでなく、これらのIDに基づいてすべてのことをしてくれます。
spetz83 2017年

6

これを行う最良の方法-特に複数の条件を追加する場合-は次のとおりです。

$values = array(...); // array of your values
$qb->andWhere('where', $qb->expr()->in('r.winner', $values));

値の配列に文字列が含まれている場合、引用符がエスケープされるため、展開された文字列でsetParameterメソッドを使用することはできません。


6

これは私がそれをどのように使用したかです:

->where('b.status IN (:statuses)')
->setParameters([
                'customerId' => $customerId,
                'storeId'    => $storeId,
                'statuses'   => [Status::OPEN, Status::AWAITING_APPROVAL, Status::APPROVED]
            ]);

5

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」ステートメントで使用するために適切に分解します。


2
これで問題が解決しました(括弧内:userids
MihaiRăducanu16年

2

私は好む:

$qb->andWhere($qb->expr()->in('t.user_role_id', [
    User::USER_ROLE_ID_ADVERTISER,
    User::USER_ROLE_ID_MANAGER,
]));

0
->where($qb->expr()->in('foo.bar', ':data'))
            ->setParameter('participants', $data);

以下でも動作します:

 ->andWhere($qb->expr()->in('foo.bar', ':users'))
                ->setParameter('data', $data);

0

値の配列に対してクエリを実行する必要があるこの同じシナリオに苦労しました。

以下は私のために働きました:

http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/dql-doctrine-query-language.html#where-clause

->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();

0

これは数年後のレガシーサイトでの作業です...私の人生では、->andWhere()または->expr()->in()ソリューションを機能させることができませんでした。

最後に、Doctrineのmongodb-odbリポジトリを調べて、いくつかの非常に明確なテストを見つけました。

public function testQueryWhereIn()
{ 
  $qb = $this->dm->createQueryBuilder('Documents\User');
  $choices = array('a', 'b');
  $qb->field('username')->in($choices);
  $expected = [
    'username' => ['$in' => $choices],
  ];
  $this->assertSame($expected, $qb->getQueryArray());
}

それは私のために働いた!

ここでgithubのテストを見つけることができます。あらゆる種類のナンセンスを明らかにするのに役立ちます。

注:私の設定では、可能な限りDoctrine MongoDb ODM v1.0.devを使用しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.