暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

VBA 字典 多表内连接合并查询技巧(学会了我能继续摸鱼)

Excel VBA练习 2021-07-21
1900

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


    代码还是利用了字典的关联定位功能...

    如果小伙伴有看之前的文章,相信也比较容易理解

    VBA 字典 关联定位

    第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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论