Hello,小伙伴们,大家好
今天小编上班的时候挺郁闷的,原本工作都做的好好的,看了一上午的图表书籍,摸鱼模的好不自在...
中午接到领导通知,需要做多个工作表连接合并数据,,这一要求无疑是将小编原本做好的工作全部推翻...
为此,小编模拟了一份数据,和工作差不多的样式,当然工作中的比这个复杂多了,不过思路是一样的...,同时上班的时候在领导面前叫苦也是必然的,不然怎么继续摸鱼,实际也没用几分钟就搞定...
如下图所示
两份工作表数据除姓名,年级,班级是一致的,不一样的是顺序不一样且标题有区别
先看看运行效果
代码如下
Sub Dic_JoinData()
Dim Dic As Object
Dim aData, aRes, arr, ar
Dim intx&, intY&, x&, y&, iRow&, iCol&, strInfo$
On Error Resume Next '出错继续运行
Application.DisplayAlerts = False '屏蔽弹窗及闪屏
Application.ScreenUpdating = False
Set 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) '定义结果数组大小,结果数组初始列为1
iRow = 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 If
For 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 If
x = Dic(strInfo): y = Dic(ar(1, intY)) '从字典中提取对应的Item 既结果数组的行与列
aRes(x, y) = ar(intx, intY) '写入数据源元素
Next
Next
Next
Worksheets("汇总").Delete '删除汇总工作表
With Sheets.Add(after:=Sheets(Sheets.Count)) '新建工作表,并且命名为汇总
.Name = "汇总"
End With
With Worksheets("汇总")
.Range("a1").Resize(iRow, iCol) = aRes '输出内容
.UsedRange.Borders.ColorIndex = 23 '添加边框
End With
Set Dic = Nothing '释放字典内存
Application.DisplayAlerts = True '恢复系统设置
Application.ScreenUpdating = True
End Sub
代码还是利用了字典的关联定位功能...
如果小伙伴有看之前的文章,相信也比较容易理解
第13至31行遍历两个工作表数据源
第15至20行循环数组列判断字典中是否存在标题关键字,如没有存入字典,并且结果数组的列位置作为关键字(Key)标题的条目(Item),也就是我们常说的定位导航定位
第21至29行巡皇数组行,既然有了列,就要找行了,利用字典的唯一关键字的特性,定位结果数组的行位置
第27行提取连接新的字符串对应的行位置以及标题对应的列位置
...
如果是SQL就比较简单了
代码如下
Sub SQL_JoinData()
Dim Conn As Object, Rec As Object
Dim aField, intx&, Sht As Worksheet
Dim strSQL$, strSource$, strSource1$
On Error Resume Next
Application.DisplayAlerts = False '屏蔽弹窗及闪屏
Application.ScreenUpdating = False
Set 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.FullName
Else
Conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Extended Properties='Excel 12.0;HDR=yes;IMEX=0';Data Source=" & ThisWorkbook.FullName
End If
strSource = "[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开始,所以每次都需要+1
aField(intx + 1) = Rec.Fields(intx).Name
Next
Worksheets("汇总").Delete '删除汇总工作表
With Sheets.Add(after:=Sheets(Sheets.Count)) '新建工作表,并且命名为汇总
.Name = "汇总"
End With
With Worksheets("汇总")
.Range("A1").Resize(, UBound(aField)) = aField '写入字段
.Range("A2").CopyFromRecordset Rec '使用单元格CopyFromRecordset方法将Rec记录写入到指定单元格
.UsedRange.Borders.ColorIndex = 23 '添加边框
End With
Conn.Close '关闭连接
Set Conn = Nothing '释放
Set Rec = Nothing '释放
Application.DisplayAlerts = True '恢复系统设置
Application.ScreenUpdating = True
End 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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。