问题
Let's say in a scenario: $ids = 2,3
. But for some reason the records are getting returned as if: $ids = 2
.
I believe there's some problem in this line from the complete code, because when I echo $ids
, it returns 2,3
, but the actual query returns as if there's only one id. I.e. it returns events from one course only (of id 2).
$statement->execute(array("ids" => $ids, 'timestart' => $timestart, 'timeend' => $timeend))) {
my full code:
$ids = array_map(function($item) { return $item->id; }, $entitlementsVOs);
$ids = implode(', ', $ids); //echo shows 2,3
$timestart = isset($_GET['start']) && $_GET['start'] != "" ? $_GET['start'] : null;
$timeend = isset($_GET['end']) && $_GET['end'] != "" ? $_GET['end'] : null;
$statement = $this->connection->prepare("SELECT name AS title, timestart AS start, timestart + timeduration AS end FROM event WHERE courseid IN(:ids) AND timestart >= :timestart AND timestart + timeduration <= :timeend");
$statement->setFetchMode(\PDO::FETCH_CLASS, get_class(new EventVO()));
if($statement->execute(array("ids" => $ids, 'timestart' => $timestart, 'timeend' => $timeend))) {
return $statement->fetchAll();
} else {
return null;
}
p.s. manually running this query in mysql workbench returns my two records (1 from course id 2 and the other from course 3) where I substitute in operator with (2,3), but in php execution I get only one record back.
If I hard code the values in php courseid IN(2,3)
, e.g.:
$statement = $this->connection->prepare("SELECT name AS title, timestart AS start, timestart + timeduration AS end FROM event WHERE courseid IN(2,3) AND timestart >= :timestart AND timestart + timeduration <= :timeend");
I get what I'm expecting, so I believe there's some problem with either implode
, or IN
operator or $statement->execute
.
Edit:
I've read the dupe, but I don't know where to start with the named placeholders to accomplish the same. My question is when I've both named parameters and IN operator, the dupe uses IN operator only with position placeholders.
Edit 2
I've read the second dupe, it's not related, my question uses a mix of both IN and named placeholders, the linked question doesn't address that, however, I've got the solution now in the answer.
回答1:
This should work for you:
So as already said in the comments you need a placeholder for each value which you want to bind into the IN clause.
Here I create first the array $ids
which only holds the plain ids, e.g.
[2, 3]
Then I also created the array $preparedIds
which holds the placeholders as array, which you then later use in the prepared statement. This array looks something like this:
[":id2", ":id3"]
And I also create an array called $preparedValues
which holds the $preparedIds
as keys and $ids
as values, which you then later can use for the execute()
call. The array look something like this:
[":id2" => 2, ":id3" => 3]
After this you are good to go. In the prepared statement I just implode()
the $preparedIds
array, so that the SQL statement look something like this:
... IN(:id2,:id3) ...
And then you can simply execute()
your query. There I just array_merge()
your $preparedValues
array with the other placeholders array.
<?php
$ids = array_map(function($item){
return $item->id;
}, $entitlementsVOs);
$preparedIds = array_map(function($v){
return ":id$v";
}, $ids);
$preparedValues = array_combine($preparedIds, $ids);
$timestart = (!empty($_GET['start']) ? $_GET['start'] : NULL );
$timeend = (!empty($_GET['end']) ? $_GET['end'] : NULL );
$statement = $this->connection->prepare("SELECT name AS title, timestart AS start, timestart + timeduration AS end FROM event WHERE courseid IN(" . implode(",", $preparedIds) . ") AND timestart >= :timestart AND timestart + timeduration <= :timeend");
$statement->setFetchMode(\PDO::FETCH_CLASS, get_class(new EventVO()));
if($statement->execute(array_merge($preparedValues, ["timestart" => $timestart, "timeend" => $timeend]))) {
return $statement->fetchAll();
} else {
return null;
}
?>
Also I think you want to put an if statement around your query, since your query will not run if the values of $timestart
and $timeend
are NULL.
来源:https://stackoverflow.com/questions/29977652/pdo-prepared-statements-in-clause-with-named-placeholders-doesnt-work-as-expect