今天同事给我一个需要更新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;
这样就可以批量生成大量的报表然后进行更新。
从一开始我就犯了一个愚蠢的错误。
我把语句转化成这样,然后快速编辑了一下,但是执行语句之后发现没有生效,真是奇怪,我把一条语句单独提取出来执行,发现结果有这样的提示,受影响的行有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
原来是语句中的where子句让我写了and,这个语句居然执行成功了,我就想看看这种语句的逻辑到底是什么。
创建一个包含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)
然后用这个奇怪的方法看看执行结果是什么。
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)
所以这个问题提出了一个非常有趣的问题。
修改语句之后数据还是没有变化,这时候就遇到了一个奇怪的问题。
上述语句手动复制时可以正常执行,但是在文本中却无法执行,我试了好多次,依然可以复现,这让我怀疑自己的运气了。
情况大致是这样的,通过缩小范围,我们就能找到修剪的部分。
手动执行可以看到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这样的符号,是我们看不见的。
既然明白了原因,我回溯这个过程,发现这个制表符还是有可能在我使用文本编辑器的时候产生的。虽然不能直接怪罪工具,但确实是我自己造成的。当然,由于这个过程中看不到字符,所以我也没太注意。
同事也给我提供了一个很有意思的类似问题,我们来看看吧,这种问题会让你质疑自己的人生。
扫一扫在手机端查看
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。