MySQL update set 和 and的區別

2022-09-21 23:36:09 字數 4521 閱讀 1368

最近接到乙個奇怪的諮詢,update 語句執行沒有報錯,但是沒有更新資料,具體有問題的語句類似於如下形式:

update test.stu set cname = '0' and math = 90 and his = 80 where id = 100;

直觀上看,這個 update 語句的語法是有問題的,正常更新多列資料的語法應該是用逗號,類似於如下形式:

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,8程式設計客棧9,92);

insert into stu values(103,'adam','2',87,89,92);

然後分別試一試正常的 update 語句和使用 and 的 update 語句,看一下實際的執行結果:

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>

可以看到這兩個語句確實都不會報錯,且帶 and 的 update 語句匹配到了具體的行(rows matched: 1),但是沒有修改資料(changed: 0),標準語法下的 update 語句倒是正常修改了資料。

由此可見,mysql 在語法上,並不認為 and 這個用法是錯誤的,那麼說明 mysql 用另外的方式「解讀」了這個語句。最容易想到的,就是 mysql 是不是在 set 的時候,把 and 解釋成了邏輯運算子,而不是英文意義上的「和」?而且 cname 的取值本來就是 0,也符合資料庫處理 bool 資料時的行為(用 0 和 1 代替 false 和 true)。

驗證起來很簡單,換個 cname 不為 0 的資料 update 一下就可以了:

mysql> select * frwww.cppcns.comom 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,也會www.cppcns.com被當做 false。

目前並不能通過 sql_mode 或者其他引數的形式來阻止這種帶 and 的 update 語句,因此這一類問題的隱蔽性比較強。建議在開發的時候,利用封裝好的框架,或者加強**或者 sql review 來避免這個問題。

pdksjirjmls:騰訊雲資料庫 mysql 也會有類似的問題,需要警惕。

和 區別和聯絡, 和 區別和聯絡

和 區別和聯絡,和 區別和聯絡,實際專案中,什麼情況用哪種?首先,和 的聯絡 共同點 和 都可以用作 邏輯與 運算子,都是雙目運算子。具體要看使用時的具體條件來決定。無論使用哪種運算子,對最終的運算結果都沒有影響。情況1 當上述的運算元是boolean型別變數時,和 都可以用作邏輯與運算子。情況2 ...

rpx和樣式和class和flex

5 style 靜態的樣式統一寫到 class 中。style 接收動態的樣式,在執行時會進行解析,請盡量避免將靜態的樣式寫進 style 中,以免影響渲染速度。例 6 class 用於指定樣式規則,其屬性值是樣式規則中類選擇器名 樣式類名 的集合,樣式類名不需要帶上.樣式類名之間用空格分隔。關於f...

if和switch和for語句

if和switch很像。具體什麼場景下,應用那個語句呢?如果判斷的具體數值不多,而是符合byte,short,int,char,字串。這五種型別。雖然兩個語句都可以使用,建議使用switch語句,因為效率稍高。其他情況,對區間判斷,對結果為boolean型別判斷,使用if,if的使用範圍更廣。whi...