(2023年5月)
SQL文内でLIMITを変数にするとエラーになる事案。
$sql = "SELECT * FROM `テーブル名` ORDER BY `id` DESC LIMIT '$limit'" ;
↑ エラー ↑
確か、以前もコレで「?」となッたンで、書ゐておく。
-----
以下は、idの条件を変数($id)にしており、1200は整数型ではないが、問題なく通る。
$id = "1200" ;
print gettype($id) ;
← string(文字列型)
$sql = "SELECT * FROM `テーブル名` WHERE `id` >= '$id' ORDER BY `id` DESC LIMIT 10" ;
1200が整数型ではないのは、「”」(ダブルクォーテーション)や「’」(シングルクォーテーション)で囲っているから。
以下のように囲わないか、
$id = 1200 ;
以下のように、囲っていても、キャスト演算子で(強引に)変換すれば、整数型となる。
$id = (int)"1200" ;
$id = (int)'1200' ;
また、「`」(バッククォート,Shift+@)内でも変数は使えるので、テーブル名を動的に変えることもできる。
$table_name = "test_table" ;
$sql = "SELECT * FROM `$table_name` WHERE `id` >= '$id' ORDER BY `id` DESC LIMIT 10" ;
この場合は、二重に囲う(`’$table_name’`)とエラーとなる。
さて、ここからが本題。
同様に、LIMITの指定を変数にすると、それが整数型であってもエラーとなる。
$limit = 10 ;
print gettype($limit) ;
← integer(整数型)
$sql = "SELECT * FROM `テーブル名` ORDER BY `id` DESC LIMIT '$limit'" ;
↑ エラー ↑
この場合は、$limitを囲わなければ通る。
$sql = "SELECT * FROM `テーブル名` ORDER BY `id` DESC LIMIT $limit" ;
これは、LIMITには数値しか許されないが、囲うことで$limitが文字列になってしまうからという理解でOK?
だが、$limitを囲わなければ、文字列型でも通るのはなンで?
なお、以下のように$limitを外に出して「.」で結合すれば通るし、これも、$limitが文字列型であっても通る。
$sql = "SELECT * FROM `テーブル名` ORDER BY `id` DESC LIMIT ".$limit ;
まぁ、コレはごッつダサゐンでヤランけど。
SQL文内に複数の変数を使用することもあるが、全て「’」で囲っているので、LIMIT時にハマッちまうのだ。
というか、SQL文内の変数は囲わないのがデフォ?
まぁ、「LIMITだけクセモノなンで妖虫遺!!」というコトだけ記憶しておけばゐ々ンかはシラン(SILANE)。
プリペアドステートメント
てコトで、プリペアドステートメントのbindValueでアレするかね…
$sql = "SELECT * FROM `テーブル名` ORDER BY `id` DESC LIMIT :limit" ;
$stmt = $pdo -> prepare($sql);
$stmt -> bindValue(":limit",$limit) ;
$stmt -> execute() ;
bindValueを使うと、$limitはシングルクォーテーションで囲わないので、数値で通るハヅ。
これを使うと、NULL(ヌルゥ!)を入れたいのに、NULLが「’NULL’」により文字列になって入らない!というのも回避できる。
なお、bindValueは変数/値ともに入るが、bindParamは変数のみなので注意。
bindValueは即座に変数を評価し、bindParamはその後のexecuteされた時点で変数を評価する。
関連:[怪奇文] MySQLのINのヴァクァ詐加減www [ゐクァれ]
関連:[MySQL] テーブルのエクスポートで、レコード数の不一致が生じる問題 [phpMyAdmin,Dump all rows]
関連:[MySQL] ランキングなどで順位を取得する方法 [自己結合]
関連:[MySQL] idを詰める(連番を振り直す)方法とAUTO_INCREMENTのリセット [DB]
関連:[MySQL] index定義の無駄と、indexが役に立たない場合 [悪例,アンチパターン]