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 07 MySQL
MySQL 角色(role)功能介绍
Apr 24 MySQL
MySQL InnoDB ReplicaSet(副本集)简单介绍
Apr 24 MySQL
SQL实现LeetCode(196.删除重复邮箱)
Aug 07 MySQL
关于mysql中时间日期类型和字符串类型的选择
Nov 27 MySQL
实战 快速定位MySQL的慢SQL
Mar 22 MySQL
MySQL中rank() over、dense_rank() over、row_number() over用法介绍
Mar 23 MySQL
MySQL中IO问题的深入分析与优化
Apr 02 MySQL
MySQL视图概念以及相关应用
Apr 19 MySQL
mysql sql常用语句大全
Jun 21 MySQL
前端传参数进行Mybatis调用mysql存储过程执行返回值详解
Aug 14 MySQL
MySql统计函数COUNT的具体使用详解
Aug 14 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
基于qmail的完整WEBMAIL解决方案安装详解
2006/10/09 PHP
php FPDF类库应用实现代码
2009/03/20 PHP
php生成不重复随机数、数组的4种方法分享
2015/03/30 PHP
启用Csrf后POST数据时出现的400错误
2015/07/05 PHP
PHP YII框架开发小技巧之模型(models)中rules自定义验证规则
2015/11/16 PHP
laravel5.6框架操作数据curd写法(查询构建器)实例分析
2020/01/26 PHP
tp5.0框架隐藏index.php入口文件及模块和控制器的方法分析
2020/02/11 PHP
纯CSS3实现质感细腻丝滑按钮
2021/03/09 HTML / CSS
Javascript自定义函数判断网站访问类型是PC还是移动终端
2014/01/10 Javascript
与Math.pow 相反的函数使用介绍
2014/08/04 Javascript
jQuery插件Tmpl的简单使用方法
2015/04/27 Javascript
jQuery实现的导航动画效果(附demo源码)
2016/04/01 Javascript
Vue.js bootstrap前端实现分页和排序
2017/03/10 Javascript
详解react-native-fs插件的使用以及遇到的坑
2017/09/12 Javascript
浅谈vue中慎用style的scoped属性
2017/11/28 Javascript
vuex与组件联合使用的方法
2018/05/10 Javascript
解决eclipse中没有js代码提示的问题
2018/10/10 Javascript
基于vue+uniapp直播项目实现uni-app仿抖音/陌陌直播室功能
2019/11/12 Javascript
Vue实现剪贴板复制功能
2019/12/31 Javascript
Python实现二分法算法实例
2015/02/02 Python
Python基于分析Ajax请求实现抓取今日头条街拍图集功能示例
2018/07/19 Python
Casadei卡萨蒂官网:意大利奢侈鞋履品牌
2017/10/28 全球购物
什么是设计模式
2012/06/17 面试题
外贸业务员求职自荐信分享
2013/09/21 职场文书
副总经理工作职责
2013/11/28 职场文书
肯尼迪就职演说稿
2013/12/31 职场文书
函授本科自我鉴定
2014/02/04 职场文书
秋季开学典礼主持词
2014/03/19 职场文书
理想点亮人生演讲稿
2014/05/21 职场文书
党的群众路线教育实践活动整改落实情况自查报告
2014/10/28 职场文书
整改报告格式
2014/11/06 职场文书
2015年幼儿园中班工作总结
2015/04/25 职场文书
民事起诉状范文
2015/05/19 职场文书
葬礼主持词
2015/07/02 职场文书
JavaScript使用canvas绘制坐标和线
2021/04/28 Javascript
MySQL优化之慢日志查询
2022/06/10 MySQL