背景前几天,由于工作需要,组长给我安排了一个数据清洗任务。任务:把A表的数据洗到B表。我的第一反应是,什么是“洗”?什么是数据清洗?我知道洗钱。但是我不能慌张,所以我问了组长。我:组长,把A表的数据洗到B表是什么意思?组长一脸无奈,用手捂住脸,恨铁不成钢,才调整过来,耐心的跟我说。大概意思就是我们现在需要A表中的数据在B表中,A表和B表中的字段意思是一样的,但是值可能不一样,这就需要我们去处理,获取数据在从A表获取数据到B表的过程中正确。基于我有限的理解能力,当时并没有真正理解所谓的“洗数据”,A表的字段不匹配B表中的字段。A中的字段明显多于B表中的字段,并且有些字段的名称不同。和B不一样,意思是一样的,怎么洗?于是疯狂搜索怎么洗数据!这里我举个例子来说明一下,分别给定表A和表B,当然我只列出了一部分字段,现在假设有这么多字段。A表A表字段:name,province_id,city_id,area_id,tech_id,crop_id,field_id,create_time,update_time,xxx,yyy,zzz,...A表字段比B表多,我需要转A表的数据被洗到B表,只处理我需要的字段,不需要的字段忽略掉。A表有20000多条记录,B表有200多条自己插入的记录。当然,在给出A表之后,再给出一个实体模型(JavaBean,Entity,supervariety,fancy)publicclassA{privateStringname;privateLongprovinceId;私人长城号;privateLongareaId;私人龙技术;私有长cropId;私人日期创建时间;私人日期更新时间;...}B表B表字段:name,province_id,city_id,area_id,mature_id,crop_id,create_time,update_time下面恢复站点我在测试环境模拟数据库两张表,上面是A表(2万多条记录,这里我只模拟了7),下面是表B(200多条记录)。洗数据的思路首先,我先找出A表中能匹配B表含义的字段,然后将A表中的数据全部插入到B表中。于是,我找到了如下字段:name,province_id,city_id,area_id,tech_id,crop_id,update_time,然后对B表新插入的数据进行处理,即洗数据。编写SQL操作的主要SQL语句为:INSERTINTOtargettable(field1,field2,...)SELECTfield1,field2,...FROMsourcetableWHEREcondition;因此,操作如下:INSERTINTOb(name,province_id,city_id,area_id,mature_id,crop_id,update_time)SELECTname,province_id,city_id,area_id,tech_id,crop_id,update_timeFROMa;运行正常,A中20000多条记录已经成功插入到B中。但!我错过了一个字段,它是create_time。于是,想着更新这个字段,将A中的这个字段更新为B。所以我写了一条SQL语句。UPDATEb(create_time)SETcreate_time=(SELECTcreate_timeFROMa);>1064-你的SQL语法有错误;查看你的MySQL服务器版本对应的手册,在第1行的'(create_time)SETcreate_time=(SELECTcreate_timeFROMa)'附近使用正确的语法哦,好像不能这样更新!(我以前打了个大嘴巴,到现在还没发现自己写错了)另一种写法:UPDATEbAStb,(SELECTcreate_timeFROMa)AStaSETtb.create_time=ta.create_time;是的,噩梦开始了!好久没更新了,看到十几秒的SQL执行完六七百秒了,着实慌了!眼看数据库要崩溃了,只好求助组长!这时候问题就出现了,有些人连接不上数据库。看得出来,这种认真程度,已经影响到其他人的使用了!于是我的组长就过来帮我处理了,想着把我的navicat杀掉,但是杀掉还是不行,毕竟SQL已经在执行了。我:你能重启这个MySQL服务吗?领队带着一连串的炮弹来了。领队:重启?你知道有多少人在用这个MySQL吗?不只是我们,你让其他人怎么重启?我很无语,很紧张,以为我惹事了,GG,就看着他操作。没过多久,经过他的手术,问题终于解决了。心中悬着的一块巨石终于放下了,好在化解了。领队牛逼,救世主!我:怎么解决?组长:回滚这个事务,更新后的SQL怎么写?(试着回忆)所以我写了上面的SQL:UPDATEbAStb,(SELECTcreate_timeFROMa)AStaSETtb.create_time=ta.create_time;领队:你为什么要写这个?子查询不应该写在SETtb.create_time之后吗?我:是的,一开始我在它后面写了这个子查询,但是它提醒我语法错误,所以我改变了写法。组长:那你写你说的提示错误的SQL。所以我抛出了另一个SQL:UPDATEbSETcreate_time=(SELECTcreate_timeFROMa);其实这个SQL也是不行的,子查询返回的结果不止一行,当前SET是更新某一行。正确的写法是:UPDATEbAStbSETcreate_time=(SELECTcreate_timeFROMaAStaWHEREtb.id=ta.idANDtb.name=ta.name)最后,组长深思,你的B表已经有两万多条记录了,你的A表也有两万多条记录。这样更新的话,每次都需要找出A表中20000多条记录,B也有20000多条记录,成为笛卡尔积。你知道笛卡尔积是什么吗?2万×2万=4亿条记录,怪不得这么久。让我重新操作一下,所以现在我会在原来的SQL上加一个WHERE条件,这样写:UPDATEbAStb,(SELECTcreate_time,nameFROMa)AStaSETtb.create_time=ta.create_timeWHEREtb。id=ta。idANDtb.name=ta.name;总结情况:某字段X缺失,需要将A表中该字段的列值更新到B表中条件:A中id字段的值等于B表中id字段的值value,A中name字段的值等于B中name字段的值(为什么条件要这样写?)。条件这样写主要是因为表之间的关系可能有多个字段,这里只选择两个字段,等等。操作:将一张表的数据插入另一张表,可以这样写:INSERTINTO目标表(字段1,字段2,...)SELECT字段1,字段2,...FROM源表WHERE条件;batch将一个表中的某个字段更新到另一个表中,SQL可以这样写:#Writing1UPDATEbAStbSETcreate_time=(SELECTcreate_timeFROMaAStaWHEREtb.id=ta.idANDtb.name=ta.name)#写法2UPDATEbAStb,(SELECTcreate_time,nameFROMa)AStaSETtb.create_time=ta.create_timeWHEREtb.id=ta.idANDtb.name=ta.name;所谓数据清洗:在我的理解中,就是根据新数据的规则,对旧数据的错误值进行修正,同时将旧数据插入到新数据中,成为新数据。例如表A中的province_id值为10代表广东,表B中的province_id值为19代表广东。在将A表的数据插入到B表的过程中,将值从10改为19,这样插入的数据就可以在B表中正确表示广东。这个过程就是“数据清洗”。当然插入后也可以修改。教训:对于数据量大的表,很少在测试环境下操作。操作时,尽量保证写的SQL是正确的。能在本地环境下操作就可以在本地环境下操作!可以用Java代码操作,先写Java代码!最后一篇受限于本人水平,难免有错误和不足之处。如果你发现了什么,请指出!最后,感谢您阅读本文,感谢您认真对待我的努力,希望这篇博客对您有所帮助!你轻轻竖起大拇指,那会为我心中的世界增添一颗璀璨耀眼的星!
