最近、データベース テーブルの特定のフィールドをバッチ更新するという要件があり、この要件を実行する際にパラメーターのバインドに PDO が使用されましたが、落とし穴に遭遇しました。
スキームの選択
著者は、バッチ更新について次の解決策を知っています:
1. 1 つずつ更新
これは最も単純な解決策ですが、間違いなく最も効率が低い解決策です。
2. CASE WHEN
以下のような文
<span>UPDATE</span> tbl_test <span>SET</span> val <span>=</span><span>CASE</span> id <span>WHEN</span><span>1</span><span>THEN</span><span>2</span><span>WHEN</span><span>2</span><span>THEN</span><span>3</span><span>END</span><span>WHERE</span> id <span>IN</span>(<span>1</span>, <span>2</span>);
PDOバインディングパラメータ
SQLインジェクションを防ぐために、PDO拡張バインディングパラメータが使用されます。上記の数値は通常変数であるため、パラメーターのバインドが必要です。最初は、ID で構成される文字列を IN 中に変数としてバインドすることを考えていました。最初の実装のコードは次のとおりです。
<span> 1</span> <?<span>php </span><span> 2</span><span>$data</span> = <span>array</span>(<span>array</span>('id' => 1, 'val' => 2), <span>array</span>('id' => 2, 'val' => 3<span>)); </span><span> 3</span><span>$ids</span> = <span>implode</span>(',', <span>array_map</span>(<span>function</span>(<span>$v</span>) {<span>return</span><span>$v</span>['id'];}, <span>$data</span>)); <span>//</span><span>获取ID数组</span><span> 4</span><span>$update_sql</span> = 'UPDATE tbl_test SET val = CASE id'<span>; </span><span> 5</span><span>$params</span> = <span>array</span><span>(); </span><span> 6</span><span>$params</span>[":ids"] = <span>$ids</span><span>; </span><span> 7</span><span>foreach</span>(<span>$data</span><span>as</span><span>$key</span> => <span>$item</span><span>) { </span><span> 8</span><span>$update_sql</span> .= "WHEN :id_" . <span>$key</span> . "THEN :val_" . <span>$key</span> . " "<span>; </span><span> 9</span><span>$params</span>[":id_" . <span>$key</span>] = <span>$item</span>['id'<span>]; </span><span>10</span><span>$params</span>[":val_" . <span>$key</span>] = <span>$item</span>['val'<span>]; </span><span>11</span><span> } </span><span>12</span><span>$update_sql</span> .= "END WHERE id IN (:_ids)"<span>; </span><span>13</span><span>TEST::</span>execute(<span>$update_sql</span>, <span>$params</span>);//此处会调用bindParam绑定参数
後で、これが機能しないことがわかりましたが、奇妙なことに、これは可能です。最初のレコードのみを更新します。情報を調べたところ、このバインド方法は実行可能ではなく、IN ステートメントのパラメータを 1 つずつバインドする必要があることがわかりました。ドキュメント内のbindParam関数の説明を見てください:
この説明では、PHP変数がプレースホルダーにバインドされると書かれていることがわかります。そのため、IDが1と2の文字列がバインドされている場合、 MySQL がステートメントを解析するとき、1 と 2 を文字列として扱うのではなく、個々の変数に解析します。これは、SQL インジェクションを防ぐ PDO の原理でもあり、プレースホルダーのバインドを通じて、バインドされた値のみが値として扱われ、ステートメントなどの他の値は値として扱われません。 。
修正された記述:
<span> 1</span> <?<span>php </span><span> 2</span><span>$data</span> = <span>array</span>(<span>array</span>('id' => 1, 'val' => 2), <span>array</span>('id' => 2, 'val' => 3<span>)); </span><span> 3</span><span>$update_sql</span> = 'UPDATE tbl_test SET val = CASE id'<span>; </span><span> 4</span><span>$params</span> = <span>array</span><span>(); </span><span> 5</span><span>$params</span>[":ids"] = <span>$ids</span><span>; </span><span> 6</span><span>$in_arr</span> = <span>array</span><span>(); </span><span> 7</span><span> 8</span><span>foreach</span>(<span>$data</span><span>as</span><span>$key</span> => <span>$item</span><span>) { </span><span> 9</span><span>$update_sql</span> .= "WHEN :id_" . <span>$key</span> . "THEN :val_" . <span>$key</span> . " "<span>; </span><span>10</span><span>$params</span>[":id_" . <span>$key</span>] = <span>$item</span>['id'<span>]; </span><span>11</span><span>$params</span>[":val_" . <span>$key</span>] = <span>$item</span>['val'<span>]; </span><span>12</span><span>$params</span>[":ids_" . <span>$key</span>] = <span>$item</span>['id'<span>]; </span><span>13</span><span>array_push</span>(<span>$in_arr</span>, ":id_" . <span>$key</span><span>); </span><span>14</span><span> } </span><span>15</span><span>$update_sql</span> .= "END WHERE id IN (" . <span>implode</span>(',' <span>$in_arr</span>) . ")"<span>; </span><span>16</span> TEST::execute(<span>$update_sql</span>, <span>$params</span>);<span>//</span><span>此处会调用bindParam绑定参数</span>
概要
これは、私が最近遭遇した小さな問題です。実際、これは、MySQL の IN ステートメントでパラメーターを 1 つずつバインドする必要があることを説明するためのものです。
参考リンク:
mysql ステートメント: 複数のレコードの異なる値を一括更新
配列を IN() 条件にバインドできますか?
限られた書き方と浅い知識によるオリジナル記事 間違っている点があれば。記事内で、申し訳ありませんが、お知らせください。
この記事が役に立った場合は、おすすめをクリックしてください。記事を書くのは簡単ではありません。
上記では、PHP の PDO 拡張機能を使用して、php および PDO コンテンツを含むバッチ更新操作を実行する [PDO バインディング パラメーター] を紹介しました。PHP チュートリアルに興味のある友人に役立つことを願っています。