SQL Server 複数の値をバインドするとき

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をループして値をセットできるようになる。

つづく。