Cách sử dụng WHERE IN với Học thuyết 2


124

Tôi có mã sau đây cho tôi lỗi:

Message: Invalid parameter number: number of bound variables does not match number of tokens 

Mã số:

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

Dữ liệu (hoặc $ id):

Array
(
    [0] => 566
    [1] => 569
    [2] => 571
)

Kết quả DQL:

q = SELECT COUNT(r.id) FROM \My\Entity\Rating r WHERE r.winner IN('?1')

1
Tôi nghĩ rằng đây là cách được đề xuất docs.doctrine-project.org/projects/doctrine-dbal/en/latest/ Kẻ
martin

Câu trả lời:


114

Trong nghiên cứu vấn đề này, tôi đã tìm thấy một cái gì đó sẽ quan trọng đối với bất kỳ ai gặp phải vấn đề tương tự này và tìm kiếm một giải pháp.

Từ bài viết gốc, dòng mã sau:

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

Việc gói tham số được đặt tên dưới dạng một mảng gây ra vấn đề về số tham số bị ràng buộc. Bằng cách loại bỏ nó khỏi gói mảng của nó:

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

Vấn đề này cần được khắc phục. Đây có thể là một vấn đề trong các phiên bản trước của Doctrine, nhưng nó đã được sửa trong các phiên bản 2.0 mới nhất.


5
Tôi nghĩ rằng $qb->expr()->in()chỉ có trong Học thuyết 2 ORM, nhưng không có trong Học thuyết DBAL.
martin

3
$qb->expr()->in()thực sự là trong
DBAL

343

Cách dễ nhất để làm điều đó là bằng cách ràng buộc chính mảng đó như một tham số:

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

41
Không chỉ mà bắt đầu từ 2.1
Maciej Pyszyński

7
@ MaciejPyszyński +1. Những cách dễ nhất thường là những cách tốt nhất!
Andrzej Ośmiałowski

2
Đề cập nhanh: Điều này hoạt động theo mặc định với -> setParameter ('ids', $ ids) nhưng không phải với -> setParameter ('ids' => $ ids). Mất vài phút để gỡ lỗi.
larrydahooster

3
để thực hiện là hoạt động với -> setParameter (...) ->where('b.status IN (:statuses)') ->setParameters([ 'customerId' => $customerId, 'storeId' => $storeId, 'statuses' => [Status::OPEN, Status::AWAITING_APPROVAL, Status::APPROVED] ]);
George Mylonas

5
Tôi muốn chỉ ra tầm quan trọng của việc truyền tham số thứ 3 setParameterđể bắt buộcConnection::PARAM_STR_ARRAY
Luc Wollants

58

và để hoàn thành giải pháp chuỗi

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

Chắc chắn là giải pháp tốt nhất cho tôi :-)
Francesco Casula

3
Cũng có thể sử dụng \ Doctrine \ DBAL \ Connection :: PARAM_INT_ARRAY nếu bạn có một mảng các số nguyên không phải là chuỗi.
Omn


12

Tôi biết đó là một bài viết cũ nhưng có thể hữu ích cho ai đó. Tôi sẽ bỏ phiếu và nâng cao câu trả lời @Daniel Espendiller bằng cách giải quyết câu hỏi được hỏi trong các nhận xét về ints

Để thực hiện công việc này cho int theo cách thích hợp, hãy đảm bảo các giá trị trong mảng là kiểu int, bạn có thể nhập cast vào int trước khi chuyển ...

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

Đã thử nghiệm để chọn / xóa trong symfony 3.4 & doctrine-bundle: 1.8


8

Tôi biết ví dụ của OP đang sử dụng DQL và trình xây dựng truy vấn, nhưng tôi tình cờ tìm thấy cách thực hiện nó từ bộ điều khiển hoặc bên ngoài lớp kho lưu trữ, vì vậy có lẽ điều này sẽ giúp người khác.

Bạn cũng có thể thực hiện WHERE INtừ bộ điều khiển theo cách này:

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

1
Đó là một cách hoàn toàn có thể chấp nhận để thực hiện một nơi mà không sử dụng DQL, nhưng câu hỏi của anh ta có liên quan đến mã DQL của anh ta. Anh ấy đang làm nhiều hơn là chỉ đơn giản cho tôi tất cả mọi thứ dựa trên những ID này.
spetz83

6

Cách tốt nhất để làm điều này - đặc biệt nếu bạn thêm nhiều hơn một điều kiện - là:

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

Nếu mảng giá trị của bạn chứa chuỗi, bạn không thể sử dụng phương thức setParameter với chuỗi được mã hóa, vì dấu ngoặc kép của bạn sẽ được thoát!


6

Đây là cách tôi sử dụng nó:

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

5

Tìm thấy cách thực hiện trong năm 2016: https://redbeardtechnology.wordpress.com/2011/07/01/doctrine-2-dql-in-statement/

Trích dẫn:

Đây là cách làm đúng:

$em->createQuery(“SELECT users 
     FROM Entities\User users 
     WHERE 
         users.id IN (:userids)”)
->setParameters(
     array(‘userids => $userIds)
);

Phương thức setParametersnày sẽ lấy mảng đã cho và mã hóa nó đúng cách để được sử dụng trong câu lệnh IN IN.


2
Điều này đã giải quyết vấn đề của tôi (dấu ngoặc đơn xung quanh :userids)
Mihai Răducanu

2

Tôi thích:

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

Cũng hoạt động với:

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

0

Tôi đã vật lộn với kịch bản tương tự mà tôi phải thực hiện một truy vấn đối với một loạt các giá trị.

Sau đây làm việc cho tôi:

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

->andWhereIn("[fieldname]", [array[]])

Ví dụ dữ liệu mảng (làm việc với chuỗi và số nguyên):

$ids = array(1, 2, 3, 4);

Ví dụ truy vấn (Thích ứng với nơi bạn cần):

$q = dataTable::getInstance()
    ->createQuery()
    ->where("name = ?",'John')
    ->andWhereIn("image_id", $ids)
    ->orderBy('date_created ASC')
    ->limit(100);

$q->execute();

0

Đây là nhiều năm sau, làm việc trên một trang web cũ ... Đối với cuộc sống của tôi, tôi không thể có được các giải pháp ->andWhere()hoặc hoạt ->expr()->in()động.

Cuối cùng tìm kiếm trong repo của Doctrine mongodb-odb và tìm thấy một số thử nghiệm rất tiết lộ:

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

Nó làm việc cho tôi!

Bạn có thể tìm thấy các bài kiểm tra trên github tại đây . Hữu ích để làm rõ tất cả các loại vô nghĩa.

Lưu ý: Thiết lập của tôi đang sử dụng Doctrine MongoDb ODM v1.0.dev theo như tôi có thể thực hiện.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.