PHPのPDOで複数のidのデータをまとめて取ってくるとかで WHERE IN を使おうとしてハマったのでメモ。
配列のまま渡しても取得できない。
<?php $ids = [1, 2, 3]; $pdo = new PDO(); $sql = "SELECT * FROM {$table} WHERE id IN (:ids)"; $stmt = $pdo->prepare($sql); $stmt->bindValue(':ids', $ids, PDO::PARAM_INT); $stmt->execute(); $res = $stmt->fetchAll(); var_dump($res); // => DBに該当するデータがあっても取得できない }
配列を文字列化してみる。
WHERE id in (1, 2, 3)
という形式になれば良いはずなので、idの配列をimplode()
関数でコンマ区切りに文字列連結してみました。
<?php $ids = [1, 2, 3]; // implode で '1, 2, 3' という文字列にしてしまう ids_str = implode(',', $ids); $pdo = new PDO(); $sql = "SELECT * FROM {$table} WHERE id IN (:ids)"; $stmt = $pdo->prepare($sql); $stmt->bindValue(':ids', $ids_str, PDO::PARAM_INT); // $ids_str が Stringなのにエラーにならない $stmt->execute(); $res = $stmt->fetchAll(); // => array(1) id = 1 のデータだけが取得される
なぜか、配列の先頭の値のものだけがSELECTされるようです。
配列の先頭の値に該当するデータが無かったらarray(0) { }
が返ってきます。
どうやら配列の先頭の値だけが評価されるみたいです。
note. '(1, 2, 3)' という文字列をプレースホルダにはできない
<?php $ids = [1, 2, 3]; // '(1, 2, 3)' という文字列にしてしまう ids_str = '(' . implode(',', $ids) . ')'; $pdo = new PDO(); $sql = "SELECT * FROM {$table} WHERE id IN :ids"; $stmt = $pdo->prepare($sql); // => Fatal error
SQLのプレースホルダが (?, ?, ?) になるようにすればOK
WHERE id in (?, ?, ?)
というSQLを作成てし、$stmt->execute()に プレースホルダに該当する値の配列を渡せば、意図した通りにデータを取ってくることができました。
<?php $ids = [1, 2, 3]; // IN 句に入る値を作成 $inClause = substr(str_repeat(',?', count($ids)), 1); // '?,?,?' $sql = "SELECT * FROM {$table} WHERE id IN ({$inClause})"; $stmt = $pdo->prepare($sql); // プレースホルダが ? の時 execute() に配列で渡すことが出来る。 $stmt->execute( $ids ); $res = $stmt->fetchAll(); // => id が 1 or 2 or 3 のデータが取得できる
ただ、execute()
に配列を渡す方法は、値が全てPDO::PARAM_STR
として扱われてしまうようなので、注意が必要かもです。
PDOStatement::execute
public bool PDOStatement::execute ([ array $input_parameters ] )
input_parameters
[参考]
SQL 第2版 ゼロからはじめるデータベース操作 (プログラミング学習シリーズ)
- 作者: ミック
- 出版社/メーカー: 翔泳社
- 発売日: 2016/06/17
- メディア: 大型本
- この商品を含むブログを見る