PDO クエリの IN() 条件に配列をバインドできますか? 質問する

PDO クエリの IN() 条件に配列をバインドできますか? 質問する

PDO を使用して値の配列をプレースホルダーにバインドできるかどうか知りたいです。ここでの使用例は、条件で使用するために値の配列を渡そうとすることですIN()

次のようなことができるようになりたいです:

<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>

そして、PDO で配列内のすべての値をバインドして引用符で囲みます。

現時点では、次のことを行っています:

<?php
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
foreach($ids as &$val)
    $val=$db->quote($val); //iterate through array and quote
$in = implode(',',$ids); //create comma separated list
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN('.$in.')'
);
$stmt->execute();
?>

確かにこれで目的は達成できますが、私が見逃している組み込みソリューションがあるかどうか疑問に思っています。

ベストアンサー1

プレースホルダーのリストを手動で作成し、配列メンバーごとにプレースホルダーを追加する必要があります。

<?php
$ids     = [1, 2, 3, 7, 8, 9];
$inQuery = str_repeat('?,', count($arr) - 1) . '?'; // gets ?,?,?,?,?,?

$stmt = $db->prepare("SELECT * FROM table WHERE id IN($inQuery)");
$stmt->execute($ids);
$data = $stmt->fetchAll();

$inQuery入力を一切受け取らず、定数値 (?,部分 ) から完全に構築されるため、クエリにこのような変数を追加しても安全です。

クエリ内に他のプレースホルダーがある場合は、array_merge()関数を使用してすべての変数を 1 つの配列に結合し、他の変数を配列の形式でクエリ内に表示される順序で追加することができます。

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

名前付きプレースホルダーを使用している場合は、名前付きプレースホルダーのシーケンスを作成する必要があるため、コードは少し複雑になります:id0,:id1,:id2。つまり、コードは次のようになります。

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

$ids = [1,2,3];
$in = "";
$i = 0; // we are using an external counter 
        // because the actual array keys could be dangerous
foreach ($ids as $item)
{
    $key = ":id".$i++;
    $in .= ($in ? "," : "") . $key; // :id0,:id1,:id2
    $in_params[$key] = $item; // collecting values into a key-value array
}

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

幸いなことに、名前付きプレースホルダーの場合は厳密な順序に従う必要がないため、配列を任意の順序で結合できます。

おすすめ記事