Home » Php » mysql – PHP – Using PDO with IN clause array

mysql – PHP – Using PDO with IN clause array

Posted by: admin February 25, 2020 Leave a comment


I’m using PDO to execute a statement with an IN clause that uses an array for it’s values:

$in_array = array(1, 2, 3);
$in_values = implode(',', $in_array);
$my_result = $wbdb->prepare("SELECT * FROM my_table WHERE my_value IN (".$in_values.")");
$my_results = $my_result->fetchAll();

The above code works perfectly fine, but my question is why this doesn’t:

 $in_array = array(1, 2, 3);
    $in_values = implode(',', $in_array);
    $my_result = $wbdb->prepare("SELECT * FROM my_table WHERE my_value IN (:in_values)");
    $my_result->execute(array(':in_values' => $in_values));
    $my_results = $my_result->fetchAll();

This code will return the item who’s my_value equals the first item in the $in_array (1), but not the remaining items in the array (2, and 3).

How to&Answers:

PDO is not good with such things. You need to create a string with question marks dynamically and insert into query.

$in  = str_repeat('?,', count($in_array) - 1) . '?';
$sql = "SELECT * FROM my_table WHERE my_value IN ($in)";
$stm = $db->prepare($sql);
$data = $stm->fetchAll();

In case there are other placeholders in the query, you could use the following approach (the code is taken from my PDO tutorial):

You could use array_merge() function to join all the variables into a single array, adding your other variables in the form of arrays, in the order they appear in your query:

$arr = [1,2,3];
$in  = str_repeat('?,', count($arr) - 1) . '?';
$sql = "SELECT * FROM table WHERE foo=? AND column IN ($in) AND bar=? AND baz=?";
$stm = $db->prepare($sql);
$params = array_merge([$foo], $arr, [$bar, $baz]);
$data = $stm->fetchAll();

In case you are using named placeholders, the code would be a little more complex, as you have to create a sequence of the named placeholders, e.g. :id0,:id1,:id2. So the code would be:

// other parameters that are going into query
$params = ["foo" => "foo", "bar" => "bar"];

$ids = [1,2,3];
$in = "";
foreach ($ids as $i => $item)
    $key = ":id".$i;
    $in .= "$key,";
    $in_params[$key] = $item; // collecting values into key-value array
$in = rtrim($in,","); // :id0,:id1,:id2

$sql = "SELECT * FROM table WHERE foo=:foo AND id IN ($in) AND bar=:bar";
$stm = $db->prepare($sql);
$stm->execute(array_merge($params,$in_params)); // just merge two arrays
$data = $stm->fetchAll();

Luckily, for the named placeholders we don’t have to follow the strict order, so we can merge our arrays in any order.


Variable substitution in PDO prepared statements doesn’t support arrays. It’s one for one.

You can get around that problem by generating the number of placeholders you need based on the length of the array.

$variables = array ('1', '2', '3');
$placeholders = str_repeat ('?, ',  count ($variables) - 1) . '?';

$query = $pdo -> prepare ("SELECT * FROM table WHERE column IN($placeholders)");
if ($query -> execute ($variables)) {
    // ...


As PDO doesn’t seem to provide a good solution, you might as well consider using DBAL, which mostly follows PDO’s API, but also adds some useful features http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion

$stmt = $conn->executeQuery('SELECT * FROM articles WHERE id IN (?)',
    array(array(1, 2, 3, 4, 5, 6)),

There are probably some other packages out there that don’t add complexity and don’t obscure the interaction with the database (like most ORM do), but at the same time make small typical tasks bit easier.


As I understand it it is because PDO will treat the $in_values contents as a single item and will quite it accordingly. PDO will see 1,2,3 as a single string so the query will look something like

SELECT * FROM table WHERE my_value IN (“1,2,3”)

You may think that changing the implode to have quotes and commas will fix it, but it will not. PDO will see the quotes and change how it quotes the string.

As to why your query matches the first value, I have no explanation.


I’ve just come up against this problem and coded a small wrapper. It’s not the prettiest or best code I’m sure, but it might help somebody so here it is:

function runQuery(PDO $PDO, string $sql, array $params = [])
    if (!count($params)) {
        return $PDO->query($sql);

    foreach ($params as $key => $values) {
        if (is_array($values)) {
            // get placeholder from array, e.g. ids => [7,12,3] would be ':ids'
            $oldPlaceholder  = ':'.$key;
            $newPlaceholders = '';
            $newParams = [];
            // loop through array to create new placeholders & new named parameters
            for($i = 1; $i <= count($values); $i++) {
                // this gives us :ids1, :ids2, :ids3 etc
                $newKey = $oldPlaceholder.$i;
                $newPlaceholders .= $newKey.', ';
                // this builds an associative array of the new named parameters
                $newParams[$newKey] = $values[$i - 1];
            //trim off the trailing comma and space
            $newPlaceholders = rtrim($newPlaceholders, ', ');

            // remove the old parameter

            // and replace with the new ones
            $params = array_merge($params, $newParams);

            // amend the query
            $sql = str_replace($oldPlaceholder, $newPlaceholders, $sql);

    $statement = $PDO->prepare($sql);
    return $statement;

E.g, passing these in:

SELECT * FROM users WHERE userId IN (:ids)

array(1) {
  array(3) {


SELECT * FROM users WHERE userId IN (:ids1, :ids2, :ids3)

array(3) {

It’s not bulletproof, but as a sole dev for my needs it does the job fine, so far anyway.


Here is a solution for unnamed placeholders (?). If you pass $sql with question mark like “A=? AND B IN(?) “ and $args where some of the elements are arrays like [1, [1,2,3]] it will return SQL string with appropriate number of placeholders – “A=? AND B IN(?,?,?)”.
It needs $args parameter only to find which element is array and how many placeholders it needs.
You can find the small PDO extension class with this method that will run your query:

public function replaceArrayPlaceholders($sql, $args)
    $num = 0;
    preg_match_all('/\?/', $sql, $matches, PREG_OFFSET_CAPTURE);  // Captures positions of placeholders
    //echo $matches[0][1][1];
    $replacements = [];
    foreach($args as $arg) {
        if(is_array($arg)) {
            $replacements[$matches[0][$num][1]] = implode(',',array_fill(0, count($arg), '?')); // Create placeholders string
    foreach($replacements as $position => $placeholders) {
        $sql = substr($sql, 0, $position).$placeholders.substr($sql, $position+1); // Replace single placeholder with multiple
    return $sql;


An alternative version of PHP Delusions (@your-common-sense) using closures:

$filter      = ["min_price" => "1.98"];
$editions    = [1,2,10];

$editions = array_combine(
    array_map(function($i){ return ':id'.$i; }, array_keys($editions)),
$in_placeholders = implode(',', array_keys($editions));
$sql = "SELECT * FROM books WHERE price >= :min_price AND edition IN ($in_placeholders)";
$stm = $pdo->prepare($sql);
$data = $stm->fetchAll();