Reputation: 19294
I'm trying to pass an array to a model which has a query. I'm not sure how to correctly pass the array or if I have to manipulate the array somehow.
I have this array:
Array
(
[0] => 1
[1] => 2
)
I have a controller with this line:
$ratings = $this->login_model->get_ratings($mechanicIds); // get the mechanic ratings
I have this model:
function get_ratings($mechanicId)
{
$sql = "select m.mechanic_id,
m.mechanic_name,
m.city,
m.state,
count(mr.rating_id) as num_ratings,
round(avg(mr.rating_id),2) avg_rating
from mechanic m, mechanic_rating mr, rating r
where m.mechanic_id in (?)
and m.mechanic_id = mr.mechanic_id
and mr.rating_id = r.rating_id";
$query = $this->db->query($sql, $mechanicId);
if ($query->num_rows() > 0) {
return $query->result_array();
} else {
return false;
}
}
It actually returns results, but the problem is it only returns the results 1 row when it should be returning 2 since there are 2 results in my array. Anyone know what I'm doing wrong?
Upvotes: 2
Views: 12442
Reputation: 47894
To pass an array into a raw query (not built with helper methods) for an IN
condition, use the ?
placeholder without wrapping in parentheses.
When binding the array to the placeholder, you must declare your array inside of an array. In other words, the "parameters" (2nd) argument of query()
method expects an array which relates to each ?
in the SQL string. Because the first ?
is bound to an array, the $mechanicIds
array must be declared as the first element of the "parameters" argument. I have tested this advice to work successfully in a CodeIgniter3 instance that I have access to.
$sql = "SELECT m.mechanic_id,
m.mechanic_name,
m.city,
m.state,
COUNT(mr.rating_id) AS num_ratings,
ROUND(AVG(mr.rating_id), 2) AS avg_rating
FROM mechanic AS m,
mechanic_rating AS mr,
rating AS r
WHERE m.mechanic_id IN ? /* <--- here */
AND m.mechanic_id = mr.mechanic_id
AND mr.rating_id = r.rating_id";
$query = $this->db->query($sql, [$mechanicIds]);
The DB_driver.php core file contains this portion of code in compile_binds()
which escapes each value in the array and wraps the comma-joined string in parentheses before returning the sql string.
...
do
{
$c--;
$escaped_value = $this->escape($binds[$c]);
if (is_array($escaped_value))
{
$escaped_value = '('.implode(',', $escaped_value).')';
}
$sql = substr_replace($sql, $escaped_value, $matches[0][$c][1], $ml);
}
while ($c !== 0);
...
Upvotes: 0
Reputation: 19294
I found this question which helped.
Below is the code I used.
Controller that contains this:
$mIds_size = count($mIds);
$i = 1;
foreach($mIds as $row)
{
if($i == $mIds_size)
{
$mechanicIds .= $row;
}
else
{
$mechanicIds .= $row.', ';
}
$i++;
}
$ratings = $this->login_model->get_ratings($mechanicIds); // get the mechanic ratings
Model which contains this:
function get_ratings($mechanicId)
{
$this->db->escape($mechanicId);
$sql = "select m.mechanic_id,
m.mechanic_name,
m.city,
m.state,
count(mr.rating_id) as num_ratings,
round(avg(mr.rating_id),2) avg_rating
from mechanic m, mechanic_rating mr, rating r
where m.mechanic_id in ($mechanicId)
and m.mechanic_id = mr.mechanic_id
and mr.rating_id = r.rating_id
group by mechanic_id";
$query = $this->db->query($sql, $mechanicId);
if($query->num_rows() > 0)
{
return $query->result_array();
}
else
{
return false;
}
}
Upvotes: 2
Reputation: 2281
Change this line:
$query = $this->db->query($sql, $mechanicId);
to this:
$query = $this->db->query($sql, array(implode(', ',$mechanicId)));
as per the manual
Upvotes: 0