วิธีใช้ WHERE IN กับหลักคำสอน 2


126

ฉันมีรหัสต่อไปนี้ซึ่งทำให้ฉันมีข้อผิดพลาด:

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/…
มาร์ติน

คำตอบ:


115

ในการค้นคว้าปัญหานี้ฉันพบบางสิ่งที่สำคัญสำหรับทุกคนที่พบปัญหาเดียวกันนี้และกำลังมองหาวิธีแก้ไข

จากโพสต์ต้นฉบับบรรทัดรหัสต่อไปนี้:

$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()อยู่ในหลักคำสอน 2 ORM เท่านั้น แต่ไม่ใช่ใน Doctrine DBAL
martin

3
$qb->expr()->in()อยู่ใน DBAL
JamesHalsall

345

วิธีที่ง่ายที่สุดคือการผูกอาร์เรย์เป็นพารามิเตอร์:

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

41
ไม่เพียง แต่เริ่มตั้งแต่วันที่ 2.1
Maciej Pyszyński

7
@ MaciejPyszyński +1. วิธีที่ง่ายที่สุดมักเป็นวิธีที่ดีที่สุด!
Andrzej Ośmiałowski

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] ]);
George Mylonas

5
ฉันอยากจะชี้ให้เห็นถึงความสำคัญของการส่งพารามิเตอร์ที่ 3 setParameterเพื่อบังคับConnection::PARAM_STR_ARRAY
Luc Wollants

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 ถ้าคุณมีอาร์เรย์ของจำนวนเต็มไม่ใช่สตริง
รอบ


12

ฉันรู้ว่ามันเป็นโพสต์เก่า แต่อาจเป็นประโยชน์สำหรับใครบางคน ฉันจะลงคะแนนและปรับปรุงคำตอบของ @Daniel Espendiller โดยตอบคำถามที่ถามในความคิดเห็นเกี่ยวกับ ints

เพื่อให้ int ทำงานได้อย่างถูกต้องตรวจสอบให้แน่ใจว่าค่าในอาร์เรย์เป็นประเภท int คุณสามารถพิมพ์ cast to int ก่อนที่จะผ่าน ...

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

ผ่านการทดสอบสำหรับ select / delete ใน symfony 3.4 & doctrine-bundle: 1.8


8

ฉันรู้ว่าตัวอย่างของ OP ใช้ DQL และตัวสร้างแบบสอบถาม แต่ฉันสะดุดกับสิ่งนี้โดยมองหาวิธีการทำจากคอนโทรลเลอร์หรือนอกคลาสที่เก็บดังนั้นบางทีนี่อาจช่วยคนอื่นได้

คุณสามารถทำWHERE INจากคอนโทรลเลอร์ด้วยวิธีนี้:

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

1
นั่นเป็นวิธีที่ยอมรับได้อย่างสมบูรณ์แบบในการทำ Where In โดยไม่ต้องใช้ DQL แต่คำถามของเขาอ้างอิงถึงรหัส DQL ของเขา เขาทำมากกว่าแค่ง่ายๆให้ทุกสิ่งตามรหัสเหล่านี้แก่ฉัน
spetz83

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

พบวิธีทำในปี 2559: 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)
Mihai Răducanu

2

ฉันชอบ:

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


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()ใช้งานได้

ในที่สุดก็ดูใน repo ของ 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.