两个看似奇怪的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这样的符号,是不可见的。

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

 

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

两个看似奇怪的MySQL语句问题_数据库_02