MySQL udate setとandの違い


問題の説明
最近、変な問い合わせを受けました。udate文の実行にはエラーはありませんでしたが、データを更新していません。具体的に問題がある文は次のような形です。

update test.stu set cname = '0' and math = 90 and his = 80 where id = 100;
原因分析
直観的に見ると、このudate文の文法は問題があります。正常に複数の列のデータを更新する文法はカンマを使うべきです。次のような形です。

update test.stu set cname = '0',math = 90,his = 80 where id = 100;
直接and第一反応を使うと、文法エラーを報告するので、正常に実行できるようには見えません。さて、騰訊雲データベースMySQLに基づいて、実際に簡単なシーンを作って、この問題を再現してみましょう。
SQL文は以下の通りです

CREATE TABLE `stu` (
  `id` int(11) NOT NULL,
  `sname` varchar(16) NOT NULL,
  `cname` varchar(8) DEFAULT NULL,
  `math` int(11) NOT NULL,
  `eng` int(11) DEFAULT NULL,
  `his` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

insert into stu values(100,'sam','0',90,88,83);
insert into stu values(101,'jhon','1',97,82,81);
insert into stu values(102,'mary','2',87,89,92);
insert into stu values(103,'adam','2',87,89,92);
そしてそれぞれ正常なudate文とandのudate文を使ってみて、実際の運行結果を見てください。

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update test.stu set cname = '0' and math = 90 and his = 80 where id = 100;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> select * from stu;
+-----+-------+-------+------+------+------+
| id  | sname | cname | math | eng  | his  |
+-----+-------+-------+------+------+------+
| 100 | sam   | 0     |   90 |   88 |   83 |
| 101 | jhon  | 1     |   97 |   82 |   81 |
| 102 | mary  | 2     |   87 |   89 |   92 |
| 103 | adam  | 2     |   87 |   89 |   92 |
+-----+-------+-------+------+------+------+
4 rows in set (0.00 sec)

mysql> update test.stu set cname = '0',math = 90,his = 80 where id = 100;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from stu;
+-----+-------+-------+------+------+------+
| id  | sname | cname | math | eng  | his  |
+-----+-------+-------+------+------+------+
| 100 | sam   | 0     |   90 |   88 |   80 |
| 101 | jhon  | 1     |   97 |   82 |   81 |
| 102 | mary  | 2     |   87 |   89 |   92 |
| 103 | adam  | 2     |   87 |   89 |   92 |
+-----+-------+-------+------+------+------+
4 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.01 sec)

mysql>
これらの2つの文は間違いなく、かつandのudate文を持って具体的な行にマッチしていますが、データは修正されていません。標準文法のudate文は正常にデータを修正しました。
このように、MySQLは文法的に、andという使い方が間違っているとは思わないので、MySQLが別の方法でこの文を解読したということを説明しています。一番思いやすいのは、MySQLはsetの時に、andを論理演算子に解釈して、英語の意味での「和」ではないですか?また、cnameの取得値はもともと0であり、データベースでbootデータを処理する際の行為(FalseとTrueの代わりに0と1を使う)にも該当します。
検証するのは簡単です。cnameを0に変えないデータをudateしてください。

mysql> select * from stu;
+-----+-------+-------+------+------+------+
| id  | sname | cname | math | eng  | his  |
+-----+-------+-------+------+------+------+
| 100 | sam   | 0     |   90 |   88 |   83 |
| 101 | jhon  | 1     |   97 |   82 |   81 |
| 102 | mary  | 2     |   87 |   89 |   92 |
| 103 | adam  | 2     |   87 |   89 |   92 |
+-----+-------+-------+------+------+------+
4 rows in set (0.00 sec)

mysql> begin;update test.stu set cname = '0' and math = 90 and his = 80 where id = 101;
Query OK, 0 rows affected (0.00 sec)

Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from stu;
+-----+-------+-------+------+------+------+
| id  | sname | cname | math | eng  | his  |
+-----+-------+-------+------+------+------+
| 100 | sam   | 0     |   90 |   88 |   83 |
| 101 | jhon  | 0     |   97 |   82 |   81 |
| 102 | mary  | 2     |   87 |   89 |   92 |
| 103 | adam  | 2     |   87 |   89 |   92 |
+-----+-------+-------+------+------+------+
4 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
結果から、MySQLはcnameの値を0に修正しました。説明は確かに論理演算子として処理されました。この文を詳しく分析すると、MySQLは次のように処理されます。

set cname = ('0' and math = 90 and his = 80)
mathとhisの値は、where条件によってフィルタリングされた行によって決定されます。実際に上のテストのシーンに対応して、次のような論理判定になります。

'0' and 97 = 90 and 81 = 80
PS:文字型のデータ0でも、Falseとして扱われるので注意してください。
ソリューション
今はsqlを通過できません。modeまたは他のパラメータの形で、このようなandのudate文を阻止するために、このような問題の隠蔽性が強いです。開発に際しては、パッケージされたフレームを利用したり、コードを強化したり、SQL reviewを強化したりして、この問題を避けることを提案しています。
PS:騰訊雲データベースMySQLにも似たような問題がありますので、注意が必要です。
以上がMySQL udate setとandの違いの詳細です。MySQL udate setとandに関する資料は他の関連記事に注目してください。