012:MySQLのINT型で「4294967295」を回避する対象言語:PHP / MySQL
|
|||||||||||
キーワード:PHP MySQL 5.0.75 UNSIGNED 4294967295 INT 0 ゼロ マイナス UPDATE CASE SET SQL_MODE NO_UNSIGNED_SUBTRACTION | |||||||||||
MySQLのバージョンを4から5にアップしました。文字化けさえ気を付けていれば既存のコードをいじらなくても問題なくデータを移行できるだろう、そう思っていた時期が私にもありました。
で、しばらく運用していたらあるカラムのデータが大量に「4294967295」等とにかく巨大な数字に書き換えられてしまうという不思議。すぐに解決しましたが、もし気付けなかったならば....というドキドキが止まりません。
このカラムは次のような構造です。
|
|||||||||||
MySQL4の時代にはpointカラムの減算を以下のコードで実行していました。
$result_lock = mysql_query("LOCK TABLES `user` WRITE", $link) or die("テーブルロックの失敗:". mysql_error()); $sql = "UPDATE `user` SET `point` = `point` - 1 WHERE `name` = 'darekasan'"; $result = mysql_query($sql, $link) or die(mysql_error()); $result_lock = mysql_query("UNLOCK TABLES", $link) or die("テーブルロック解除の失敗:". mysql_error());
パターンA: 計算の結果が負となるか正となるかで条件分岐しながらUPDATE!
があります。あとトリガーを使うなんていう方法もありますけど、コードを短く・処理を少なくをモットーに1行のSQL文にこだわる管理人は、
次のようにCASE文を使用することにしました(1だけ減算する場合)。
パターンB: UNSIGNEDをMySQL4のときと同じ挙動にする! // パターンA・・・CASE文を使う // CASE文: (CASE WHEN <条件> THEN <条件が真の時> ELSE <条件が偽の時> END) $result_lock = mysql_query("LOCK TABLES `user` WRITE", $link) or die("テーブルロックの失敗:". mysql_error()); $sql = "UPDATE `user` SET `point` = (CASE WHEN `point` >= 1 THEN `point` - 1 ELSE 0 END) WHERE `name` = 'darekasan'"; $result = mysql_query($sql, $link) or die(mysql_error()); $result_lock = mysql_query("UNLOCK TABLES", $link) or die("テーブルロック解除の失敗:". mysql_error()); // パターンB・・・NO_UNSIGNED_SUBTRACTIONを事前にセットする $result_lock = mysql_query("LOCK TABLES `user` WRITE", $link) or die("テーブルロックの失敗:". mysql_error()); // 追加 $sql = "SET SQL_MODE = 'NO_UNSIGNED_SUBTRACTION'"; $result = mysql_query($sql, $link); // 以下は変更していない $sql = "UPDATE `user` SET `point` = `point` - 1 WHERE `name` = 'darekasan'"; $result = mysql_query($sql, $link) or die(mysql_error()); $result_lock = mysql_query("UNLOCK TABLES", $link) or die("テーブルロック解除の失敗:". mysql_error()); |