LoginSignup
15
5

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-12-16

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

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文を直接流す際は、十分に注意しなければなりません。

15
5
0

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
  3. You can use dark theme
What you can do with signing up
15
5