アプリ版:「スタンプのみでお礼する」機能のリリースについて

PDOでIN句を使用しているのですが、正しく動作しません。

$stmt = $pdo->prepare('SELECT * FROM hoge where id in (?)');
$stmt->bindValue(1, '123, 456, 789');
$stmt->execute();
var_dump($stmt->fetchAll());

fetchAllを行っても複数のレコードがかえってこず、ヒットした最初の1行のレコードしか取得することができません。PDOでIN句を使用することはできないのでしょうか?
DBMSはMySQLを使用して、PHPは5.2.6を使用しています。

ちなみに
$stmt = $pdo->prepare('SELECT * FROM hoge where id in (?, ?, ?)');
$stmt->bindValue(1, 123);
$stmt->bindValue(2, 456);
$stmt->bindValue(3, 789);
$stmt->execute();

では、fetchAll で複数のレコードが返ってきます。
どうしてもpreparedで単一のIN句を使いたいのですが、何か良い方法はありますでしょうか?

A 回答 (1件)

もし、? にバインドする3つの値が、ユーザーの入力と無関係で、SQLインジェクションの危険がないのなら、



直接
$stmt = $pdo->query('SELECT * FROM hoge where id in (123,456,789)');
で実行すればいいと思います。

?を使って書くのは、SQLインジェクション対策です。prepareで、構文解析を行い、実行プランを立てます。この段階で、?にはスカラー値しか入らないようになっています。ユーザーが変な値をフォームから入れても、ここには構造を持たないスカラーしか入れられません。

最初の例のように、bindしても?には'123,456,789'という文字列がbindされます。
SELECT * FROM hoge where id in ('123,456,789')

本来、これはデータ型の不一致ではじく方がいいと思いますが、MySQLはSQLとしてはデータ型に寛容ですので、idが整数の123の時は、動いてしまいます。'123,456,789'を整数として評価して、123と見ます。

つまり、
SELECT * FROM hoge where id in (123)

と考えます。結果として、idが123の行が返ります。
    • good
    • 0
この回答へのお礼

ありがとうございました。
どうやらマニュアルにもかかれているようで、まとめてIN句に指定することができないみたいでした。

http://jp2.php.net/manual/ja/pdo.prepare.php

このことから、事前にSQLを組み立てる際に、IN句に利用する値は
IN(?, ?, ?) に展開して prepare するようにします。

お礼日時:2009/01/07 09:28

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!