9b3386efdc5eecfbe1dfda559c3cd99e.png

本篇文章说一个VBA常见应用案例,批量提取工作簿中特定位置数据。作为VBA入门的学习练手的案例非常合适。搞明白搞懂,汇总工作簿之类的问题都不在话下。

→案例需求:

首先,我有一堆待提取的表(每个表里分为加工总表和成本表):

69a53ffce5acb380b5f7c2c5311e5140.png

汇总表和分表的数据对应关系如下:

加工总表:

f8b14039aac2d6d792d8af0947638f14.png
/双击查看大图

成本表:

aa54e4e0ef68585368f88fb48ddde62a.png
/双击查看大图

→思路分析:

①批量提取必定要循环打开工作簿,再找到相对应位置直接取数据。让代码代替手工去循环打开工作簿。这里我们用GetOpenFilename方法,允许使用者选择需要汇总的工作簿路径,获取之后,对GetOpenFilename方法返回的路径进行循环。具体用法可以看历史文章:获取文件全路径(一)GetOpenFilename方法

②有一个稍微难一些的地方,成本表中需要提取的数据行数位置不固定

75bd97a5ebe649a5310de97887807795.png

有的朋友可能想到用end属性,但是这里面有合并单元格,而且提取数据的周围上下都有数据,这些都是阻挡正确提取数据的地方。

这个时候就要找另外一些突破点:发现需要提取的数据都是位于【总计】这个单元格的附近。这样的话,我们就可以用Find函数查找【总计】这个单元格所在的位置,找到了他,提取他周围的单元格内容就简单多了。Find函数具体用法,详见历史文章:不得不说的高效Boy:Find方法

我觉得VBA入门的差别就在这了:会不会找规律,并将这些规律转化为代码的逻辑条件。

→代码详解:

Sub 汇总清空之前的数据()
    '//弹出窗口,让用户选择需要合并的工作簿
    pth = Application.GetOpenFilename("文件(*.xls*),*.xls*", , "请选择文件", , True) 'GetOpenFilename支持通配符,true代表允许多选。
    If Not IsArray(pth) Then '如果用户没有选择文件,则返回False,不是数组。
        MsgBox "请选择需要汇总的工作簿"
        Exit Sub '退出过程
    End If
    '//
    Application.ScreenUpdating = False '禁止刷新,防止屏幕闪烁,提高运行速度
    Application.AskToUpdateLinks = False '禁止提示更新链接
    Application.DisplayAlerts = False '禁止无关的提示信息
    Set thissht = ThisWorkbook.ActiveSheet '把代码工作簿的活动工作表赋值给对象变量thissht
    thissht.Range("a2:k10000").ClearContents '清空除标题行以外的原有数据
    For i = 1 To UBound(pth) 'GetOpenFilename多选文件的话返回的是一个数组,里面存放的是每个文件的路径,循环数组获取里面的文件路径。
        Set wb = Workbooks.Open(pth(i)) '将打开的工作簿赋值给对象变量wb
        Set sumsht = wb.Worksheets("加工总表") '将打开的工作簿的【加工总表】sheet赋值给对象变量sumsht
        Set chengbensht = wb.Worksheets("成本表") '将打开的工作簿的【成本表】sheet赋值给对象变量sumsht
        lastrow = thissht.Cells(thissht.Rows.Count, 1).End(3).Row + 1 '获取代码工作簿已使用的最大行号+1
        With thissht 'with结构,简化代码
            .Cells(lastrow, 1) = i '序号
            .Cells(lastrow, 2) = sumsht.Range("a4") '加工任务
            .Cells(lastrow, 3) = sumsht.Range("b4") '材料
            .Cells(lastrow, 4) = sumsht.Range("c4") '厚度
            .Cells(lastrow, 5) = sumsht.Range("e4") '加工时间
            .Cells(lastrow, 6) = sumsht.Range("f4") '零件总数
            Set zongji = chengbensht.UsedRange.Find("总计", , xlValues, xlWhole, xlByColumns, xlNext, True, True) 'find方法,查找【总计】关键字所在单元格
            .Cells(lastrow, 7) = chengbensht.Cells(zongji.Row, 5) '和【总计】单元格同一行,第5列的数据就是所需要的穿孔个数
            .Cells(lastrow, 8) = Replace(chengbensht.Cells(zongji.Row + 1, 5), "元/个", "") '在【总计】单元格下一行,第5列的数据就是所需要的单价
            .Cells(lastrow, 9) = chengbensht.Cells(zongji.Row, 6) '理解同上
            .Cells(lastrow, 10) = Replace(chengbensht.Cells(zongji.Row + 1, 6), "元/m", "") '理解同上
            .Cells(lastrow, 11) = Replace(chengbensht.Cells(zongji.Row + 2, 5), "元", "") '理解同上
            '上述几句可以用offset实现。
        End With
        wb.Close False '关闭打开的工作簿,直接用对象变量wb.clsoe即可。false表示不保存。
    Next
    Application.ScreenUpdating = True '开启刷新
    Application.AskToUpdateLinks = True '开启提示更新链接
    Application.DisplayAlerts = True '开启无关的提示信息
    MsgBox "完成!"
End Sub

上述查找到【总计】单元格的位置之后,还可以用offset方法找到周围的单元格,这个可以自己试着写一下。

→写在最后:

很多人说VBA怎么入门,迟迟不能入门,也有一些人迟迟摇摆不定到底学不学VBA,恐怕多刚学会VBA就被废弃了。

▪是否值得学我想说的是,担心太多余了,技多不压身,学习VBA给你带来的效率回报,可能是你自己都想不到的。VBA,用了都说好。

▪关于迟迟不能入门第一个是知识点的积累:比如文中说的Find方法,你没学过这个,根本想不到当行数不确定的时候怎么获取。所以,一定的知识点积累是必要的。百度、问人或者刷教程都可以。

第二个是一定要敲代码:就算抄一遍也会有很多收获,因为你可能抄都抄不对。我刚开始入门的时候,自己写代码。表示单元格的Cells到底加不加s都会有疑问,Worksheets都拼不对。

推荐阅读:(点击下方标题即可跳转)

  • 【建议收藏】VBA说历史文章汇总
  • 速码工具箱2.0发布,更强大的功能等你来体验!
  • VBA会被Python代替吗?
  • 代码存储美化工具测评-【VBE2019】
  • Excel和Word数据交互读取(生成合同)
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐