k0pernikus
k0pernikus

Reputation: 66589

How to fetchAllBySql with a WHERE IN clause using [email protected]?

A legacy project uses [email protected]. I want to create a query inside a CActiveRecord.

The query in raw sql would be:

SELECT column
FROM table
WHERE some_id in (1, 32, 10)

and it works fine when I query the DB directly. I get all the results.

I map that in my active record (class MyActiveRecord extends CActiveRecord) via following method in yii:

    public function getColumn(array $someIds): array
    {
        $idList = rtrim(implode(', ', $someIds), ', ');
        $sql    = "SELECT column FROM table WHERE some_id IN (:idList)";

        $results = parent::model(__CLASS__)->findAllBySql(
            $sql,
            ['idList' => $idList]
        );

        return array_column($results, 'column');
    }

The code works but it strangely only fetches the result of the first some_id. How do I fetch all of them?

Say that my for my id 1 I have 5 results, for 32 I have 3, and for 10 I have 2 results, I expect a total of 10 records.

Yet I only get back the 5 results for the id 1 within yii. What am I doing wrong?

(When I changed the order of the id, always only the first id will be fetched, the others ignored.)

Upvotes: 0

Views: 995

Answers (2)

rob006
rob006

Reputation: 22174

Your code will create query like SELECT column FROM table WHERE some_id IN ('1, 32, 10') - you're using one param and it is passed to query as one string value. To pass each ID independently, you must use multiple params:

$results = parent::model(__CLASS__)->findAllBySql(
   'SELECT column FROM table WHERE some_id IN (:id1, :id2, :id3)',
    ['id1' => 1, 'id2' => 32, 'id3' => 10]
);

Or avoid using params and use concatenation/interpolation, but you need to sanitize/quote values first, to ensure that there is no SQL Injection risk:

$ids = implode(', ', array_map('intval', $someIds);
$results = parent::model(__CLASS__)->findAllBySql(
   "SELECT column FROM table WHERE some_id IN ($ids)"
);

But probably the most safe and convenient option is to use CDbCommand to build your query:

$result = Yii::app()->db->createCommand()
    ->select('column')
    ->from('table')
    ->where(['IN', 'id', $ids])
    ->queryColumn();

Upvotes: 3

k0pernikus
k0pernikus

Reputation: 66589

I consider this a workaround but not a solution. I changed my code to use a CDbCriteria, yet I find it suboptimal as it will fetch all the fields. At least it yields my expected results:

$c = new CDbCriteria();
$c->compare('some_id', $someIds);
$result = $this->findAll($c);

return array_column($result, 'column');

Upvotes: 0

Related Questions