PDOException: SQLSTATE[IMSSP]: Tried to bind parameter number 65536. SQL Server supports a maximum of 2100 parameters
何もせずにただbindValueを使って実行すると上記のエラーが出たり、訳が分からなかった。
解決方法
SQL serverにてプレースホルダー(名前付きバインドパラメータ)を使いまわしたいとき、以下で解決する。
// prepareの前に
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$response = $db->prepare($sql);
参照
teratail
こちらにも書いてあります。
参考
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14133193124
用語説明
バインドパラメータ:SQLにおいて、値を表すパラメータの場所を指定する方法、パラメータ、プレースホルダーの一部、エスケープやクォート処理を自動で行う。
プレースホルダー:バインドパラメータと組み合わせてつかわれる。名前付きや疑問符がある。
プリペアードステートメントは、バインドぱれめーたを使用してクエリに値を挿入する。SQLインジェクション攻撃からの保護のため。
使用例
以下のSQLがあるとき、
SELECT * FROM TABLE WHERE ID = :id
条件式のなかのパラメータは変数を直接入れるのではなく、バインドして値を入れる。
その時に使うのが、バインドパラメータである。
それでは複数のパラメータがある場合はどうか。
すべてをbindValueで書く。
配列にしてパラメータ部分を数字にする。ループしてbindParamで書く。
$sql = "SELECT * FROM sample WHERE id= :id and name= :name and email = :email";
$stmt = $db->prepare($sql);
$values = array(
"id" => "foo",
"name" => "bar",
"email" => "baz@example.com"
);
foreach ($values as $key => $value) {
$stmt->bindParam(':' . $key, $values[$key]);
}
$stmt->execute();
やはりラベルを使いまわしたほうが簡単だろう。
MySQLならこれでできるかもしれない。
$value = "foo";
$stmt->bindParam(':param', $value);
$sql = "SELECT * FROM mytable WHERE column1 = :param OR column2 = :param";
$stmt->prepare($sql);
$stmt->execute();
しかしSQL Serverではエラーとなる。
"query err:SQLSTATE[07002]: [Microsoft][ODBC Driver 17 for SQL Server]COUNT フィールドが正しくないか、構文エラーです。"
これを回避するためにエミュレーターをONにする。
bindValueをループして値をセットできるようになる。
つづく。