MySQL udate setとandの違い
問題の説明
最近、変な問い合わせを受けました。udate文の実行にはエラーはありませんでしたが、データを更新していません。具体的に問題がある文は次のような形です。
直観的に見ると、このudate文の文法は問題があります。正常に複数の列のデータを更新する文法はカンマを使うべきです。次のような形です。
SQL文は以下の通りです
このように、MySQLは文法的に、andという使い方が間違っているとは思わないので、MySQLが別の方法でこの文を解読したということを説明しています。一番思いやすいのは、MySQLはsetの時に、andを論理演算子に解釈して、英語の意味での「和」ではないですか?また、cnameの取得値はもともと0であり、データベースでbootデータを処理する際の行為(FalseとTrueの代わりに0と1を使う)にも該当します。
検証するのは簡単です。cnameを0に変えないデータをudateしてください。
ソリューション
今はsqlを通過できません。modeまたは他のパラメータの形で、このようなandのudate文を阻止するために、このような問題の隠蔽性が強いです。開発に際しては、パッケージされたフレームを利用したり、コードを強化したり、SQL reviewを強化したりして、この問題を避けることを提案しています。
PS:騰訊雲データベースMySQLにも似たような問題がありますので、注意が必要です。
以上がMySQL udate setとandの違いの詳細です。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に関する資料は他の関連記事に注目してください。