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 05 MySQL
多表查询、事务、DCL
Apr 05 MySQL
详解MySQL数据库千万级数据查询和存储
May 18 MySQL
MySQL系列之九 mysql查询缓存及索引
Jul 02 MySQL
MySQL系列之十一 日志记录
Jul 02 MySQL
MySQL深度分页(千万级数据量如何快速分页)
Jul 25 MySQL
Mysql中where与on的区别及何时使用详析
Aug 04 MySQL
彻底解决MySQL使用中文乱码的方法
Jan 22 MySQL
详解MySQL的主键查询为什么这么快
Apr 03 MySQL
MySQL分区以及建索引的方法总结
Apr 13 MySQL
MySQL聚簇索引和非聚簇索引的区别详情
Jun 14 MySQL
MySQL transaction事务安全示例讲解
Jun 21 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
人大复印资料处理程序_输入篇
2006/10/09 PHP
PHP数组操作汇总 php数组的使用技巧
2011/07/17 PHP
PHP ? EasyUI DataGrid 资料取的方式介绍
2012/11/07 PHP
php上传大文件失败的原因及应对策略
2015/10/20 PHP
PHP中set_include_path()函数相关用法分析
2016/07/18 PHP
CentOS系统中PHP安装扩展的方式汇总
2017/04/09 PHP
PHP实现驼峰样式字符串(首字母大写)转换成下划线样式字符串的方法示例
2017/08/10 PHP
JavaScript 笔记二 Array和Date对象方法
2010/05/22 Javascript
javascript,jquery闭包概念分析
2010/06/19 Javascript
一段批量给页面上的控件赋值js
2010/06/19 Javascript
JQuery异步获取返回值中文乱码的解决方法
2015/01/29 Javascript
浅析AngularJS中的生命周期和延迟处理
2015/06/18 Javascript
EasyUi combotree 实现动态加载树节点
2016/04/01 Javascript
简单封装js的dom查询实例代码
2016/07/08 Javascript
AngularJs基本特性解析(一)
2016/07/21 Javascript
localStorage实现便签小程序
2016/11/28 Javascript
对称加密与非对称加密优缺点详解
2017/02/06 Javascript
vue2.0获取自定义属性的值
2017/03/28 Javascript
微信小程序动态添加分享数据
2017/06/14 Javascript
如何在 Vue 表单中处理图片
2021/01/26 Vue.js
python通过openpyxl生成Excel文件的方法
2015/05/12 Python
通过Python爬虫代理IP快速增加博客阅读量
2016/12/14 Python
numpy:找到指定元素的索引示例
2019/11/26 Python
python字符串反转的四种方法详解
2019/12/02 Python
html5 浏览器支持 如何让所有的浏览器都支持HTML5标签样式
2012/12/07 HTML / CSS
印尼穆斯林时尚购物网站:Hijabenka
2016/12/10 全球购物
护理职业应聘自荐书
2013/09/29 职场文书
毕业生怎样写好自荐信
2013/11/11 职场文书
2014年商场超市庆元旦活动方案
2014/02/14 职场文书
大学活动总结格式
2014/04/29 职场文书
新学期红领巾广播稿
2014/10/04 职场文书
入党积极分子党支部意见
2015/06/02 职场文书
初中语文教师研修日志
2015/11/13 职场文书
2016年综治和平安建设宣传月活动总结
2016/04/01 职场文书
雄兵连:第三季先行图公开,天使恶魔联合,银河之力的新力量
2021/06/11 国漫
使用JS前端技术实现静态图片局部流动效果
2022/08/05 Javascript