两个看似奇怪的MySQL语句问题

时间:2022-05-05
本文章向大家介绍两个看似奇怪的MySQL语句问题,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

今天同事给了我一个文件需要更新下CMDB的数据,提供的内容是excel的形式,因为条目比较多,我需要做一些转换,批量修改成对应的SQL语句,因为只有我知道这个逻辑,所以这个转换工作由我来做。

本来看起来很简单的一个问题,结果因为不经意的操作出了两个问题,会牵扯出来两条有趣的SQL问题。

首先excel数据类似下面的形式:

TEST1 10.0.0.1  7382
TEST2 10.0.0.2  7388
TEST21 10.0.0.21  7389

所以我需要把内容做一个简单的转换,比如使用awk或者使用文本编辑器来做都可以。

我需要把数据转换成SQL语句,类似下面的形式:

update cmdb_server set server_app_code = trim('TEST1      ') where server_ip_addr=trim('10.0.0.1 ') and server_db_port=7382; 

这样就可以批量生成大量的update语句,更新即可。

我从开始就犯了一个低级错误。

我把语句给转换成了这样,很快就编辑好了,但是执行语句之后发现没有生效,真是奇怪,自己抽出一条语句来单独执行看看,发现结果竟然有这样的提示,影响到的行数有500多行,这看起来就麻烦了。

update cmdb_server set server_app_code = trim('TEST1      ') and server_ip_addr=trim('10.0.0.1 ') and server_db_port=7382;
Query OK, 0 rows affected (0.01 sec)
Rows matched: 537  Changed: 0  Warnings: 0

原来,是update语句竟然where字句部分让我写成了and,这种语句竟然能够成功执行,我想看看这类语句到底是个什么逻辑。

创建一个表test,有3个字段

mysql> create table test(col1 int,col2 varchar(30),col3 varchar(30));
Query OK, 0 rows affected (0.11 sec)

插入3条数据

mysql> mysql> insert into test values (1,'aa','aaa');
Query OK, 1 row affected (0.07 sec)
mysql> insert into test values (2,'bb','aaab');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values (3,'cc','aaac');
Query OK, 1 row affected (0.00 sec)

然后使用这种奇怪的update,看看执行的结果到底是什么样的。

mysql> update test set col1=4 and col2='cc' and col3='aaac';
Query OK, 3 rows affected (0.07 sec)
Rows matched: 3  Changed: 3  Warnings: 0

查看结果,发现会把原来的col1列给刷新,标记为0和1,如果映射到了就是1,否则就是0,但是真正的数据没有正常变更。

mysql> select *from test;
+------+------+------+
| col1 | col2 | col3 |
+------+------+------+
|    0 | aa   | aaa  |
|    0 | bb   | aaab |
|    1 | cc   | aaac |
+------+------+------+
3 rows in set (0.00 sec)

所以这个问题牵扯出来一个还蛮意思的问题。

修改语句之后,数据还是没有变更过来,这个时候碰到了一个诡异的问题,

上面的update语句手工拷贝过来能够正常执行,但是在文本里就不可以。反反复复试了多次,还可以复现,让我都有些怀疑人品了。

情况大概是这样,通过缩小范围,能够定位出来是在trim的部分。

手工执行,可以看到trim的部分是生效了。

mysql> select concat(rtrim('101022152a  '),'tttt');
+--------------------------------------+
| concat(rtrim('101022152a  '),'tttt') |
+--------------------------------------+
| 101022152atttt                       |
+--------------------------------------+
1 row in set (0.00 sec)

而如果编辑这个文件,执行的时候trim的部分却没有生效。

mysql> source a.sql

+----------------------------------------------+
| concat(trim('10.10.22.152 '),'10.10.22.152') |
+----------------------------------------------+
| 10.10.22.152 10.10.22.152                    |
+----------------------------------------------+
1 row in set (0.00 sec)

查看文件的内容

mysql> system cat a.sql 
select concat(trim('10.10.22.152 '),'10.10.22.152');

而这个问题我犹豫了一会,突然想明白了,我换个思路来解答。

我把文本中的那段内容简单修改了下,保持空格的部分不变,然后使用hex来解析。

mysql> system cat a.sql 
select hex(concat(trim('2 '),'1'));
+-----------------------------+
| hex(concat(trim('2 '),'1')) |
+-----------------------------+
| 320931                      |
+-----------------------------+
1 row in set (0.00 sec)

这个时候就明白了,32是2的ascii码值,同理,1对应的是31,而09对应的是制表符,也就是t这样的符号,是不可见的。

明白了原因,来回溯过程,会发现我使用文本编辑器的时候还是可能生成这个制表符的,不能直接把锅扣给工具,还是自己触发的,当然这个过程中因为字符不可见,所以也就没有重视。

同事也给我提供了一个蛮有意思的类似问题,大家一睹为快,这类问题简直会让你怀疑人生。