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 21 MySQL
.Net Core导入千万级数据至Mysql的步骤
May 24 MySQL
MYSQL 无法识别中文的永久解决方法
Jun 03 MySQL
分享mysql的current_timestamp小坑及解决
Nov 27 MySQL
MYSQL如何查看进程和kill进程
Mar 13 MySQL
如何创建一个创建MySQL数据库中的datetime类型
Mar 21 MySQL
Nebula Graph解决风控业务实践
Mar 31 MySQL
MYSQL优化之数据表碎片整理详解
Apr 03 MySQL
MYSQL中文乱码问题的解决方案
Jun 14 MySQL
MySQL提升大量数据查询效率的优化神器
Jul 07 MySQL
MySQL的表级锁,行级锁,排它锁和共享锁
Jul 15 MySQL
MySQL数据管理操作示例讲解
Dec 24 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获取网卡地址的代码
2008/04/09 PHP
解析php框架codeigniter中如何使用框架的session
2013/06/24 PHP
PHP_Cooikes不同页面无法传递的解决方法
2014/03/07 PHP
PHP网页缓存技术优点及代码实例
2020/07/29 PHP
jquery动态改变onclick属性导致失效的问题解决方法
2013/12/04 Javascript
用js控制组织结构图可以任意拖拽到指定位置
2014/01/17 Javascript
jquery 删除字符串最后一个字符的方法解析
2014/02/11 Javascript
node.js实现逐行读取文件内容的代码
2014/06/27 Javascript
浅谈JavaScript 覆盖原型以及更改原型
2016/08/31 Javascript
微信小程序 progress组件详解及实例代码
2016/10/25 Javascript
Vue.js 踩坑记之双向绑定
2018/05/03 Javascript
Bootstarp在pycharm中的安装及简单的使用方法
2019/04/19 Javascript
如何解决日期函数new Date()浏览器兼容性问题
2019/09/11 Javascript
vue+element导航栏高亮显示的解决方式
2019/11/12 Javascript
微信小程序开发中var that =this的用法详解
2020/01/18 Javascript
详解vue3.0 的 Composition API 的一种使用方法
2020/10/26 Javascript
python采用requests库模拟登录和抓取数据的简单示例
2014/07/05 Python
Python学习笔记之os模块使用总结
2014/11/03 Python
浅谈Python中函数的参数传递
2016/06/21 Python
python调用接口的4种方式代码实例
2019/11/19 Python
Python Celery多队列配置代码实例
2019/11/22 Python
pytorch 实现在一个优化器中设置多个网络参数的例子
2020/02/20 Python
如何理解python对象
2020/06/21 Python
python和go语言的区别是什么
2020/07/20 Python
Python 实现集合Set的示例
2020/12/21 Python
深入解析HTML5的IndexedDB索引数据库
2015/09/14 HTML / CSS
HTML5自定义属性前缀data-及dataset的使用方法(html5 新特性)
2017/08/24 HTML / CSS
优良学风班总结材料
2014/02/08 职场文书
教师对照四风自我剖析材料
2014/09/30 职场文书
会议通知范文
2015/04/15 职场文书
公司辞职信模板
2015/05/13 职场文书
爱国主义电影观后感
2015/06/18 职场文书
客户答谢会致辞
2015/07/30 职场文书
java实现对Hadoop的操作
2021/07/01 Java/Android
动态规划之使用备忘录来改进Javascript函数
2022/04/07 Javascript
Java 垃圾回收超详细讲解记忆集和卡表
2022/04/08 Java/Android