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
MySQL入门命令之函数-单行函数-流程控制函数
Apr 05 MySQL
分析MySQL抛出异常的几种常见解决方式
May 18 MySQL
MySQL中几种插入和批量语句实例详解
Sep 14 MySQL
深入解析MySQL索引数据结构
Oct 16 MySQL
一文带你探究MySQL中的NULL
Nov 11 MySQL
MySQL高级进阶sql语句总结大全
Mar 16 MySQL
mysql数据插入覆盖和时间戳的问题及解决
Mar 25 MySQL
MySQL RC事务隔离的实现
Mar 31 MySQL
MySQL数据库如何使用Shell进行连接
Apr 12 MySQL
MySQL 数据表操作
May 04 MySQL
MySQL数据库查询之多表查询总结
Aug 05 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中用date函数获取当前时间有误的解决办法
2013/08/02 PHP
ThinkPHP之foreach标签使用概述
2014/06/30 PHP
php实现给图片加灰色半透明效果的方法
2014/10/20 PHP
php中explode函数用法分析
2014/11/15 PHP
php下载文件超时时间的设置方法
2016/10/06 PHP
php表单习惯用的正则表达式
2017/10/11 PHP
php菜单/评论数据递归分级算法的实现方法
2019/08/01 PHP
Javascript技巧之不要用for in语句对数组进行遍历
2010/10/20 Javascript
Script标签与访问HTML页面详解
2014/01/10 Javascript
浅谈JavaScript中运算符的优先级
2015/07/07 Javascript
jquery动态导航插件dynamicNav用法实例分析
2015/09/06 Javascript
AngularJS 单元测试(二)详解
2016/09/21 Javascript
js实现常见的工具条效果
2017/03/02 Javascript
浅谈sass在vue注意的地方
2017/08/10 Javascript
js判断传入时间和当前时间大小实例(超简单)
2018/01/11 Javascript
浅谈vue中改elementUI默认样式引发的static与assets的区别
2018/02/03 Javascript
vue实现多条件和模糊搜索功能
2019/05/28 Javascript
Vue源码分析之Vue实例初始化详解
2019/08/25 Javascript
一篇文章带你使用Typescript封装一个Vue组件(简单易懂)
2020/06/05 Javascript
vue-cli 3如何使用vue-bootstrap-datetimepicker日期插件
2021/02/20 Vue.js
[02:28]DOTA2英雄基础教程 狼人
2013/12/23 DOTA
pytyon 带有重复的全排列
2013/08/13 Python
使用python实现ANN
2017/12/20 Python
django反向解析URL和URL命名空间的方法
2018/06/05 Python
Python实现爬虫抓取与读写、追加到excel文件操作示例
2018/06/27 Python
python Dijkstra算法实现最短路径问题的方法
2019/09/19 Python
python实现加密的方式总结
2020/01/19 Python
AmazeUI 单选框和多选框的实现示例
2020/08/18 HTML / CSS
鲜果饮品店创业计划书
2014/01/21 职场文书
机械专业毕业生自我鉴定2014
2014/10/04 职场文书
教师文明餐桌光盘行动倡议书
2015/04/28 职场文书
一个独生女的故事观后感
2015/06/04 职场文书
Redis Cluster 字段模糊匹配及删除
2021/05/27 Redis
简单总结SpringMVC拦截器的使用方法
2021/06/28 Java/Android
使用canvas对video视频某一刻截图功能
2021/09/25 HTML / CSS
apache ftpserver搭建ftp服务器
2022/05/20 Servers