Hello,小伙伴们,大家好
今天小编上班的时候挺郁闷的,原本工作都做的好好的,看了一上午的图表书籍,摸鱼模的好不自在...
中午接到领导通知,需要做多个工作表连接合并数据,,这一要求无疑是将小编原本做好的工作全部推翻...
为此,小编模拟了一份数据,和工作差不多的样式,当然工作中的比这个复杂多了,不过思路是一样的...,同时上班的时候在领导面前叫苦也是必然的,不然怎么继续摸鱼,实际也没用几分钟就搞定...
如下图所示

两份工作表数据除姓名,年级,班级是一致的,不一样的是顺序不一样且标题有区别
先看看运行效果

代码如下
Sub Dic_JoinData()Dim Dic As ObjectDim aData, aRes, arr, arDim intx&, intY&, x&, y&, iRow&, iCol&, strInfo$On Error Resume Next '出错继续运行Application.DisplayAlerts = False '屏蔽弹窗及闪屏Application.ScreenUpdating = FalseSet Dic = CreateObject("Scripting.Dictionary")aData = Worksheets("Sheet1").Range("A1").CurrentRegion '获取Sheet1工作表数据arr = Worksheets("Sheet2").Range("A1").CurrentRegion '获取Sheet2工作表数据ReDim aRes(1 To UBound(aData) + UBound(arr), 1 To 1) '定义结果数组大小,结果数组初始列为1iRow = 1 '初始化计数器For Each ar In Array(aData, arr) '遍历循环两个数据源For intY = 1 To UBound(ar, 2) '遍历循环数据源源列If Not Dic.exists(ar(1, intY)) Then '判断字典中是否包含标题关键字iCol = iCol + 1 '结果数组列累加Dic(ar(1, intY)) = iCol '标题为Key对应的Item为结果数组列位置If iCol > UBound(aRes, 2) Then ReDim Preserve aRes(1 To UBound(aRes), 1 To iCol) '重新调整结果数组大小aRes(1, iCol) = ar(1, intY) '结果数组写入标题End IfFor intx = 2 To UBound(ar) '遍历循环数据源行strInfo = ar(intx, 1) & ar(intx, 2) & ar(intx, 3) '连接新的字符串作为关键字If Not Dic.exists(strInfo) Then '判断关键字是否存在字典中iRow = iRow + 1 '累加结果数组行位置Dic(strInfo) = iRow '新的字符串为Key对应的Item为结果数组行位置End Ifx = Dic(strInfo): y = Dic(ar(1, intY)) '从字典中提取对应的Item 既结果数组的行与列aRes(x, y) = ar(intx, intY) '写入数据源元素NextNextNextWorksheets("汇总").Delete '删除汇总工作表With Sheets.Add(after:=Sheets(Sheets.Count)) '新建工作表,并且命名为汇总.Name = "汇总"End WithWith Worksheets("汇总").Range("a1").Resize(iRow, iCol) = aRes '输出内容.UsedRange.Borders.ColorIndex = 23 '添加边框End WithSet Dic = Nothing '释放字典内存Application.DisplayAlerts = True '恢复系统设置Application.ScreenUpdating = TrueEnd Sub
代码还是利用了字典的关联定位功能...
如果小伙伴有看之前的文章,相信也比较容易理解
第13至31行遍历两个工作表数据源
第15至20行循环数组列判断字典中是否存在标题关键字,如没有存入字典,并且结果数组的列位置作为关键字(Key)标题的条目(Item),也就是我们常说的定位导航定位
第21至29行巡皇数组行,既然有了列,就要找行了,利用字典的唯一关键字的特性,定位结果数组的行位置
第27行提取连接新的字符串对应的行位置以及标题对应的列位置
...
如果是SQL就比较简单了
代码如下
Sub SQL_JoinData()Dim Conn As Object, Rec As ObjectDim aField, intx&, Sht As WorksheetDim strSQL$, strSource$, strSource1$On Error Resume NextApplication.DisplayAlerts = False '屏蔽弹窗及闪屏Application.ScreenUpdating = FalseSet Conn = CreateObject("Adodb.Connection")If Application.Version < 12 Then '判断Excel的版本号,以使用不同的连接字符串Conn.Open "Provider=Microsoft.ACE.OLEDB.4.0;Extended Properties='Excel 8.0;HDR=yes;IMEX=0';Data Source=" & ThisWorkbook.FullNameElseConn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Extended Properties='Excel 12.0;HDR=yes;IMEX=0';Data Source=" & ThisWorkbook.FullNameEnd IfstrSource = "[Sheet1$]" 'Sheet1数据源strSource1 = "[Sheet2$]" 'Sheet2数据源strSQL = "Select a.*,政治,历史,化学,生物 From " & strSource & "a," & strSource1 & "b Where a.年级=b.年级 and a.班级=b.班级 and a.姓名=b.姓名"Set Rec = Conn.Execute(strSQL)ReDim aField(1 To Rec.Fields.Count) 'Fields包含了所有字段的,Fields.Count 得到字段的数量For intx = 0 To Rec.Fields.Count - 1 'Fields.Count的下标为0,因此总数-1,字段数组从1开始,所以每次都需要+1aField(intx + 1) = Rec.Fields(intx).NameNextWorksheets("汇总").Delete '删除汇总工作表With Sheets.Add(after:=Sheets(Sheets.Count)) '新建工作表,并且命名为汇总.Name = "汇总"End WithWith Worksheets("汇总").Range("A1").Resize(, UBound(aField)) = aField '写入字段.Range("A2").CopyFromRecordset Rec '使用单元格CopyFromRecordset方法将Rec记录写入到指定单元格.UsedRange.Borders.ColorIndex = 23 '添加边框End WithConn.Close '关闭连接Set Conn = Nothing '释放Set Rec = Nothing '释放Application.DisplayAlerts = True '恢复系统设置Application.ScreenUpdating = TrueEnd Sub
别看一大串,实际上基本都是固定的
需要修改的只有SQL语句以及存放的位置...
代码中的SQL语句
strSQL = "Select a.*,政治,历史,化学,生物 From " & strSource & "a," & strSource1 & "b Where a.年级=b.年级 and a.班级=b.班级 and a.姓名=b.姓名"
也可以这样写
strSQL = "Select a.*,政治,历史,化学,生物 From " & strSource & "a," & strSource1 & "b Where a.年级&a.班级&a.姓名=b.年级&b.班级&b.姓名"
在这里使用了SQL中的内连接查询,通过字段将两个表的内容一一对应起来
...
打字手软,关于内连接我们先见个面,下个月就要详细撩撩这个了
示例文件下载
链接:https://pan.baidu.com/s/138SftHsSVoRtr8ciVQu51g
提取码:abcd
收工!
如果小伙伴有好的思路,可以在小编的公众号留言发给小编研究下
文章觉得有用,点个赞+在看,你的每一次点赞和转发就是小编原创的动力
关注公众号 ↓
文章转载自Excel VBA练习,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




