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 InnoDB存储引擎的内存管理
Apr 08 MySQL
MySQL Threads_running飙升与慢查询的相关问题解决
May 08 MySQL
MySQL下使用Inplace和Online方式创建索引的教程
May 26 MySQL
MySQL快速插入一亿测试数据
Jun 23 MySQL
一文带你探究MySQL中的NULL
Nov 11 MySQL
解决Mysql多行子查询的使用及空值问题
Jan 22 MySQL
浅谈redis的过期时间设置和过期删除机制
Mar 18 MySQL
MySQL 条件查询的常用操作
Apr 28 MySQL
解决Mysql中的innoDB幻读问题
Apr 29 MySQL
MySQL 数据表操作
May 04 MySQL
MySQL实现字段分割一行转多行的示例代码
Jul 07 MySQL
MySQL 原理与优化之Update 优化
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
提高php运行速度的一些小技巧分享
2012/07/03 PHP
PHP实现获取图片颜色值的方法
2014/07/11 PHP
javascript 有用的脚本函数
2009/05/07 Javascript
javascript 获取图片尺寸及放大图片
2013/09/04 Javascript
jQuery拖拽 & 弹出层 介绍与示例
2013/12/27 Javascript
jquery操作复选框(checkbox)的12个小技巧总结
2014/02/04 Javascript
JavaScript File API文件上传预览
2016/02/02 Javascript
纯JS实现可拖拽表单的简单实例
2016/09/02 Javascript
原生JavaScript实现AJAX、JSONP
2017/02/07 Javascript
Javascript中字符串相关常用的使用方法总结
2017/03/13 Javascript
JavaScript数据结构之数组的表示方法示例
2017/04/12 Javascript
基于vue配置axios的方法步骤
2017/11/09 Javascript
React组件重构之嵌套+继承及高阶组件详解
2018/07/19 Javascript
微信小程序实现顶部下拉菜单栏
2018/11/04 Javascript
vue项目中axios请求网络接口封装的示例代码
2018/12/18 Javascript
vue.js购物车添加商品组件的方法
2019/09/17 Javascript
简单的Python的curses库使用教程
2015/04/11 Python
Python中交换两个元素的实现方法
2018/06/29 Python
Python wxpython模块响应鼠标拖动事件操作示例
2018/08/23 Python
对Python的多进程锁的使用方法详解
2019/02/18 Python
Pytorch to(device)用法
2020/01/08 Python
python opencv如何实现图片绘制
2020/01/19 Python
Python使用pyexecjs代码案例解析
2020/07/13 Python
Python pexpect模块及shell脚本except原理解析
2020/08/03 Python
python 实现简单的计算器(gui界面)
2020/11/11 Python
浅析HTML5中的 History 模式
2017/06/22 HTML / CSS
APM Monaco中国官网:来自摩纳哥珠宝品牌
2017/12/27 全球购物
韩国美国时尚服装和美容在线全球市场:KOODING
2018/11/07 全球购物
加拿大鞋网:Globo Shoes
2019/12/26 全球购物
文秘大学生求职信
2014/02/25 职场文书
学习雷锋精神演讲稿
2014/05/10 职场文书
2015年暑期社会实践活动总结
2015/03/27 职场文书
高三数学复习备考教学反思
2016/02/18 职场文书
幼儿园大班教学反思
2016/03/02 职场文书
详解RedisTemplate下Redis分布式锁引发的系列问题
2021/04/27 Redis
分析MySQL优化 index merge 后引起的死锁
2022/04/19 MySQL