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查询的控制语句图文详解
Apr 11 MySQL
MySQL 角色(role)功能介绍
Apr 24 MySQL
解决MySQL存储时间出现不一致的问题
Apr 28 MySQL
MySQL kill不掉线程的原因
May 07 MySQL
MySQL 分页查询的优化技巧
May 12 MySQL
详解MySQL连接挂死的原因
May 18 MySQL
SQL实现LeetCode(175.联合两表)
Aug 04 MySQL
SQL之各种join小结详细讲解
Aug 04 MySQL
SQL实现LeetCode(180.连续的数字)
Aug 04 MySQL
MySQL常见优化方案汇总
Jan 18 MySQL
MySQL的存储函数与存储过程的区别解析
Apr 08 MySQL
MYSQL事务的隔离级别与MVCC
May 25 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 目录与文件处理-郑阿奇(续)
2011/07/04 PHP
php创建和删除目录函数介绍和递归删除目录函数分享
2014/11/18 PHP
PHP中的类型提示(type hinting)功能介绍
2015/07/01 PHP
JavaScript入门教程(9) Document文档对象
2009/01/31 Javascript
一个简单的js渐显(fadeIn)渐隐(fadeOut)类
2010/06/19 Javascript
基于jquery的给文章加入关键字链接
2010/10/26 Javascript
网站404页面3秒后跳到首页的实例代码
2013/08/16 Javascript
JS 弹出层 定位至屏幕居中示例
2014/05/21 Javascript
JavaScript实现twitter puddles算法实例
2014/12/06 Javascript
使用Plupload实现直接上传附件至七牛云存储
2014/12/26 Javascript
jQuery中:disabled选择器用法实例
2015/01/04 Javascript
分析了一下JQuery中的extend方法实现原理
2015/02/27 Javascript
jQuery实现仿腾讯微博滑出效果报告每日天气的方法
2015/05/11 Javascript
浅谈JavaScript中promise的使用
2017/01/11 Javascript
node使用UEditor富文本编辑器的方法实例
2017/07/11 Javascript
vue.js使用v-model实现表单元素(input) 双向数据绑定功能示例
2019/03/08 Javascript
vue-mugen-scroll组件实现pc端滚动刷新
2019/08/16 Javascript
微信小程序利用for循环解决内容变更问题
2020/03/05 Javascript
Python基于递归算法实现的走迷宫问题
2017/08/04 Python
numpy中索引和切片详解
2017/12/15 Python
如何安装并使用conda指令管理python环境
2019/07/10 Python
Python解析命令行读取参数之argparse模块
2019/07/26 Python
Python Gluon参数和模块命名操作教程
2019/12/18 Python
python如何建立全零数组
2020/07/19 Python
python使用matplotlib:subplot绘制多个子图的示例
2020/09/24 Python
python实现简单的井字棋游戏(gui界面)
2021/01/22 Python
CSS3中的常用选择器使用示例整理
2016/06/13 HTML / CSS
Tory Burch英国官方网站:美国时尚生活品牌
2017/12/06 全球购物
美国职棒大联盟的官方手套、球和头盔:Rawlings
2020/02/15 全球购物
一套比较完整的软件测试人员面试题
2012/05/13 面试题
五一家具促销方案
2014/01/10 职场文书
艺术节主持词
2014/04/02 职场文书
个人思想政治总结
2015/03/05 职场文书
博士生专家推荐信
2015/03/25 职场文书
复活读书笔记
2015/06/29 职场文书
python自动统计zabbix系统监控覆盖率的示例代码
2021/04/03 Python