views:

274

answers:

3

According to http://us2.php.net/manual/en/mysqli-stmt.bind-param.php, the different types are:

i   corresponding variable has type integer
d   corresponding variable has type double
s   corresponding variable has type string
b   corresponding variable is a blob and will be sent in packets

However, how can you handle this:

->prepare("SELECT blabla FROM foo WHERE id IN (?)")

Where ? would be a list of ids. There could be one or more items:

$ids = "3,4,78";
->bind_param('s',$ids);

Is that possible?

I'd like to use prepared statements because it will be executed in a loop.

+2  A: 

The proper syntax would be

->prepare("SELECT blabla FROM foo WHERE id IN (?, ?, ?)")

for 3 items in that array, for example. You would then have to bind each of those items individually using bind_param().

If you don't have a size guarantee on the array, you'll have to write a couple helper functions to generate your SQL with the proper number of "?"'s and bind statements.

Marc W
Indeed I do not know the size in advance. If I re-write the prepared statement for each iteration of the loop (to change the number of ?s), then it defeats the purpose of prepared statements.
nute
I'm not quite sure what you want to accomplish in the loop. Will the values bound to the statement be changing each time? Are the _number_ of values bound changing? Are you executing an identical statement multiple times (don't know why you'd do this)?
Marc W
the number of values IN(?,?,?) change each loop iteration sometimes it could be (1,2,3,4), or (1,2,3,4,5,6,7,8,9) ...
nute
@nute. It may slightly defeat the speed advantage, but it still has the advantage of being safe from from malicious sql injection. You can always gain back the speed advantage of pre-preparing one statement per length-of-in clause.
Cheekysoft
A: 

I think I found the answer to my question:

->prepare("SELECT stuff FROM table_name WHERE id IN (?)");

$itemList = implode(',',$items);
$children->bind_param('s',$itemList);

Seems to be working fine when using a string with coma-separated values. I'm still checking if the results are really accurate ...

nute
Hmm, that shouldn't be working. The prepared statement should wind up being `SELECT stuff FROM table_name WHERE id IN ('1, 2, 3, 4, 5')` in that situation, which shouldn't work as you expect...
ceejayoz
No it won't work. Please don't use this code!
too much php
However it does seem to work fine so far ...If you've got a better idea, please let me know!
nute
A: 

If you have a list of variables that differs in size every call that you wanto to bind to an IN-statement, the most simple way would be to generate the SQL string programatically and use a loop to bind the variables:

/**
 * @param  array  $values
 * @param  mysqli $db
 * @return mysqli_stmt
 */
function bindInValues(array $values, mysqli $db)
{
    $sql = sprintf('SELECT blabla FROM foo WHERE id IN (%s)',
        implode(', ', array_fill(0, count($values), '?'))
    );
    $stmt = $db->prepare($sql);
    foreach ($values as $value) {
        $stmt->bind_param('s', $value);
    }
    return $stmt;
}

If you like call_user_func_array you can use dynamic method invocation and go along without a loop.

/**
 * @param  array  $values
 * @param  mysqli $db
 * @return mysqli_stmt
 */
function bindInValues(array $values, mysqli $db)
{
    $sql = sprintf('SELECT blabla FROM foo WHERE id IN (%s)',
        implode(', ', array_fill(0, count($values), '?'))
    );
    $stmt = $db->prepare($sql);
    array_unshift($values, implode('', array_fill(0, count($values), 's')));
    call_user_func_array(array($stmt, 'bind_param'), $values);
    return $stmt;
}
Stefan Gehrig
this of course means the use of Prepared Statements isn't really efficient anymore, since you're "preparing" at every iteration, instead of just once.Because I mean to send that SELECT statement many times in a row, with different number of params every time.
nute
You're right - that's the inevitable consequence... But there is no other way around.
Stefan Gehrig
If you're sending a different query (related to the SQL structure not the values) every time, you can skip the preparation step and directly build the SQL including the `IN` values.
Stefan Gehrig