MySQL update set 和 and的区别


Posted in MySQL onMay 08, 2021

问题描述

最近接到一个奇怪的咨询,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,89,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 * 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 的 update 语句,因此这一类问题的隐蔽性比较强。建议在开发的时候,利用封装好的框架,或者加强代码或者 SQL review 来避免这个问题。

PS:腾讯云数据库 MySQL 也会有类似的问题,需要警惕。

以上就是MySQL update set 和 and的区别的详细内容,更多关于MySQL update set 和 and的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
MySQL 如何分析查询性能
May 12 MySQL
MySQL完整性约束的定义与实例教程
May 30 MySQL
浅谈MySQL user权限表
Jun 18 MySQL
MySQL 发生同步延迟时Seconds_Behind_Master还为0的原因
Jun 21 MySQL
mysql如何配置白名单访问
Jun 30 MySQL
SQL实现LeetCode(175.联合两表)
Aug 04 MySQL
Mysql8.0递归查询的简单用法示例
Aug 04 MySQL
SQL实现LeetCode(177.第N高薪水)
Aug 04 MySQL
MySQL的索引你了解吗
Mar 13 MySQL
浅谈redis的过期时间设置和过期删除机制
Mar 18 MySQL
mysql 乱码 字符集latin1转UTF8
Apr 19 MySQL
MySQL提取JSON字段数据实现查询
Apr 22 MySQL
MySQL查询学习之基础查询操作
May 08 #MySQL
MySQL sql_mode修改不生效的原因及解决
May 07 #MySQL
一篇文章弄懂MySQL查询语句的执行过程
详解MySQL主从复制及读写分离
MySQL 表空间碎片的概念及相关问题解决
MySQL kill不掉线程的原因
May 07 #MySQL
MySQL数字类型自增的坑
May 07 #MySQL
You might like
在PHP中检查PHP文件是否有语法错误的方法
2009/12/23 PHP
php获取网页标题和内容函数(不包含html标签)
2014/02/03 PHP
php实现微信企业号支付个人的方法详解
2017/07/26 PHP
Laravel核心解读之异常处理的实践过程
2019/02/24 PHP
JS中==与===操作符的比较
2009/03/21 Javascript
jquery表单验证使用插件formValidator
2012/11/10 Javascript
JQuery入门—JQuery程序的代码风格详细介绍
2013/01/03 Javascript
JS实现局部选择打印和局部不选择打印
2014/04/03 Javascript
js监听鼠标事件控制textarea输入字符串的个数
2014/09/29 Javascript
javascript基础知识
2016/06/07 Javascript
javascript实现的全国省市县无刷新多级关联菜单效果代码
2016/08/01 Javascript
AngularJS基础 ng-submit 指令简单示例
2016/08/03 Javascript
AngularJs中 ng-repeat指令中实现含有自定义指令的动态html的方法
2017/01/19 Javascript
详解Nodejs之npm&package.json
2017/06/15 NodeJs
使用vue-router beforEach实现判断用户登录跳转路由筛选功能
2018/06/25 Javascript
10行代码实现微信小程序滑动tab切换
2018/12/28 Javascript
使用flow来规范javascript的变量类型
2019/09/12 Javascript
基于JavaScript伪随机正态分布代码实例
2019/11/07 Javascript
使用Python下载Bing图片(代码)
2013/11/07 Python
python字符串连接的N种方式总结
2014/09/17 Python
python基于phantomjs实现导入图片
2016/05/13 Python
Python闭包的两个注意事项(推荐)
2017/03/20 Python
Python基于socket模块实现UDP通信功能示例
2018/04/10 Python
Python中py文件引用另一个py文件变量的方法
2018/04/29 Python
python爬取内容存入Excel实例
2019/02/20 Python
Windows 下更改 jupyterlab 默认启动位置的教程详解
2020/05/18 Python
Python字节单位转换(将字节转换为K M G T)
2021/03/02 Python
阿拉伯时尚购物网站:Nisnass
2021/02/07 全球购物
Linux内核的同步机制是什么?主要有哪几种内核锁
2013/01/03 面试题
Java的类可以定义为Protected或者Private得吗
2015/09/25 面试题
应届优秀本科大学毕业生自我鉴定
2014/01/21 职场文书
建筑结构施工专业推荐信
2014/02/21 职场文书
银行奉献演讲稿
2014/09/16 职场文书
关于感恩的歌曲整理(8首)
2019/08/14 职场文书
Python尝试实现蒙特卡罗模拟期权定价
2022/04/21 Python
Python软件包安装的三种常见方法
2022/07/07 Python