LoginSignup
5

More than 5 years have passed since last update.

posted at

updated at

UPDATEのSETでANDを使ってしまうとヤバい

タイトルだけを見て、結論がわかった方もいるかもしれません。

UPDATE文では、複数カラムにデータをセットするとき、","(カンマ)で区切るのが正しいですが、
間違ってANDで区切ったときに起こりうる問題です。

テーブル定義

mysql> show create table user\G
*************************** 1. row ***************************
       Table: user
Create Table: CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` smallint(6) DEFAULT NULL,
  `yomigana` varchar(80) NOT NULL,
  `birth_date` date DEFAULT NULL,
  `prefecture` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql>

UPDATEを使って、「山田 太郎」さんに、年齢、生年月日、都道府県を設定します。

UPDATE user
   SET age = 36, birth_date = '1980-01-15', prefecture = '東京都'
 WHERE name = '山田 太郎';
UPDATE user
   SET prefecture = '東京都' AND age = 36 AND birth_date = '1980-01-15'
 WHERE name = '山田 太郎';
UPDATE user
   SET age = 36 AND birth_date = '1980-01-15' AND prefecture = '東京都'
 WHERE name = '山田 太郎';

それぞれのUPDATE文を実行すると、どうなるでしょうか。

正解は、①は正常に動作、②はエラーメッセージが出る、③はageが0か1に変化、でした。

①は、更新するカラムが","(カンマ)で区切られているため、問題ありません。

②は、prefectureに、'東京都' AND age = 36 AND birth_date = '1980-01-15'という条件を設定するという意味になります。
しかし、prefectureはVARCHAR型なので、0か1の数値は入れようとしてエラーとなります。

ERROR 1292 (22007): Truncated incorrect DOUBLE value: 

③は、ageに、36 AND birth_date = '1980-01-15' AND prefecture = '東京都'の判定結果を設定するという意味になります。
そのため、ageに0か1の値を入れることになるため、ageが0か1になります。
ほかのカラムは更新されません。

SETの最初が数値系のカラム(INT, DECIMAL, TINYINT等)だと0か1にデータが更新されます。

つまり、意図しない値にUPDATEされうるのです。
もし、これが大量のレコードに対し、0か1を設定してしまったら、悲劇にもつながるわけです。
そのため、UPDATE文を直接流す際は、十分に注意しなければなりません。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5