目录
- [零. 使用场景](#零. 使用场景)
- [一. 刷新PowerQuery表格](#一. 刷新PowerQuery表格)
-
- [1.1 方式一](#1.1 方式一)
- [1.2 方式二](#1.2 方式二)
- [1.3 方式三](#1.3 方式三)
- [二. 向带名字的表格中插入数据](#二. 向带名字的表格中插入数据)
- [三. 获取表格中的数据](#三. 获取表格中的数据)
零. 使用场景
⏹需要自动化动态的统计表格中的数据
- 使用公式:不便于维护,表格中的数据是动态变化的
- 使用VBA:不便于维护,为了统计要写很多代码
- 使用PowerQuery:
- 简单统计无需写代码
- 复杂统计写的代码较少
👍使用VBA和PowerQuery结合的方式,能更好的进行自动化处理
- Power Query 负责,获取数据 + 清洗
- VBA 负责 调度 + 控制 + 自动化
一. 刷新PowerQuery表格
🔷当一个Excel中有若干个PowerQuery创建的表格时,每次一个个的手动刷新数据太麻烦。
使用VBA创建一个按钮,一键全部刷新。
1.1 方式一
- 只需一行代码
- 刷新当前打开的整个Excel,简单粗暴,最省事
- 所有的数据连接,数据透视表都会被刷新
vbnet
Sub MainSub()
ThisWorkbook.RefreshAll
End Sub
1.2 方式二
- 先获取到PowerQuery的所有连接对象,然后找到连接名
- 然后通过连接名精确的根据连接对象进行刷新
vbnet
Sub MainSub()
Dim connectObj As WorkbookConnection
' 获取当前Excel文件中的所有连接对象
For Each connectObj In ThisWorkbook.Connections
' 打印连接名字
Debug.Print connectObj.Name ' 查询 - 表1
' 打印连接的类型
Debug.Print connectObj.Type
' Power Query 一般名字是:查询 - xxx
If InStr(connectObj.Name, "查询") > 0 Then
' 刷新连接
connectObj.Refresh
End If
Next
' 根据连接名找到连接Powerquery的连接对象, 然后刷新
ThisWorkbook.Connections("查询 - 表1").Refresh
End Sub
1.3 方式三
- 先根据表格的名称找到表格对象
- 然后使用表格对象进行刷新
vbnet
Sub MainSub()
Dim currentWs As Worksheet
Dim tbl1 As ListObject
' 获取当前打开的Excel的指定的Sheet页
Set currentWs = ThisWorkbook.Worksheets("Sheet2")
' 获取指定Sheet页中的指定表格
Set tbl1 = currentWs.ListObjects("表1_2")
' 获取当前表格的类型
' 0 普通表格
' 1 外部数据
' 2 查询
Debug.Print tbl1.SourceType
' 如果当前表格对象存在就刷新
If Not tbl1.QueryTable Is Nothing Then
tbl1.QueryTable.Refresh BackgroundQuery:=False
End If
End Sub
二. 向带名字的表格中插入数据
🔷给表格命名之后,表格对变为超级表,使用VBA操作起来更加方便
vbnet
' 强制要求变量必须要声明
' 如果变量不声明的话, 也能用, 但默认类型是Variant
' vba在使用的时候还需要默认转型
Option Explicit
Sub MainSub()
' 定义sheet对象和表对象
Dim ws As Worksheet
Dim tblObj As ListObject
' 获取指定的Sheet页对象
Set ws = ThisWorkbook.Worksheets("Sheet3")
' 获取指定Sheet页中的指定表对象
Set tblObj = ws.ListObjects("表3")
' 如果当前表格中有数据的话, 就直接清空
If tblObj.ListRows.count > 0 Then
tblObj.dataBodyRange.Delete
End If
' 定义一个字典对象
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
' 向字典对象添加key和value
dict("MPL_ERR001") = 10
dict("MPL_ERR002") = 23
dict("MPL_ERR003") = 26
dict("QCH_ERR00A") = 52
dict("QCH_ERR00B") = 45
dict("QCH_ERR00C") = 28
' 遍历字典所用到的变量
Dim key As Variant
Dim arr() As String
Dim row As ListRow
Dim rowNum As Long
' 遍历字典
For Each key In dict.Keys
' 表格新增加一行
Set row = tblObj.ListRows.Add
' 获取当前的行号
rowNum = tblObj.ListRows.count
' 通过下划线分隔字符串
arr = Split(key, "_")
' 为新增的1行的每列都添加数据
With row.Range
' 因为只有1行, 所以 → .Cells(1, 列下标)
' 第1列 → No
.Cells(1, 1) = rowNum
' 第2列 → 系统名
.Cells(1, 2) = arr(0)
' 第3列 → 错误码
.Cells(1, 3) = arr(1)
' 第4列 → 值
.Cells(1, 4) = dict(key)
End With
Next
' 设置表格的排序属性
With tblObj.Sort.SortFields
' 清除当前表格的排序
.Clear
' === 添加新的排序规则 ===
' Key:=tblObj.ListColumns(1).Range → 根据第1列排序
' SortOn:=xlSortOnValues → 根据单元格值的值排序
' Order:=xlDescending → 倒序(从大到小)
' Order:=xlAscending → 正序(从小到大)
.Add Key:=tblObj.ListColumns(1).Range, SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
End With
With tblObj.Sort
' 表示表格有表头
.Header = xlYes
' 应用排序
.Apply
End With
End Sub
三. 获取表格中的数据
🔷列数据获取方式
- 根据列名获取
- 根据列索引获取
🔷列数据遍历
- 可以先遍历获取列中的每个单元格
- 然后获取每个单元格中的数据
- 如果表格很大的话,这种方式效率较低
- 先把列中的数据全部取出,放到数组中
- 然后遍历数组即可
- 效率会高一些
vbnet
Option Explicit
Sub MainSub()
' 定义sheet对象和表对象
Dim ws As Worksheet
Dim tblObj As ListObject
' 获取指定的Sheet页对象
Set ws = ThisWorkbook.Worksheets("Sheet3")
' 获取指定Sheet页中的指定表对象
Set tblObj = ws.ListObjects("表3")
' 如果当前表格中没有数据的话, 提示用户
If tblObj.ListRows.count <= 0 Then
MsgBox "表格中没有数据, 请确认..."
Exit Sub
End If
' 表格相关变量
Dim systemNameCell As Range
Dim systemNameRange As Range
' 🔷根据表格的列名获取当前列的数据(不会包含表头的数据)
Set systemNameRange = tblObj.ListColumns("系统名").DataBodyRange
If systemNameRange Is Nothing Then
MsgBox "当前列, 没有数据..."
Exit Sub
End If
' 遍历表格中指定列的数据
For Each systemNameCell In systemNameRange
Debug.Print systemNameCell.Value
Next
Debug.Print "============================"
' 🔷根据表格的列索引来获取当前列的数据并遍历
For Each systemNameCell In tblObj.ListColumns(2).DataBodyRange
Debug.Print systemNameCell.Value
Next
Debug.Print "~~~~~~~~~~~~~~~~~~~~~~~~~~~"
' ==============================
' 👍推荐写法:
' 直接读取当前列的数组
' 然后遍历, 效率会更高
'
' 如果一个个遍历单元格的话
' 当数据多的时候, 会影响效率
' ==============================
Set systemNameRange = tblObj.ListColumns(2).DataBodyRange
If systemNameRange Is Nothing Then
MsgBox "当前列, 没有数据..."
Exit Sub
End If
' 🔷获取包含当前列中的所有的数据的数组
Dim i As Long
Dim dataArr As Variant: dataArr = systemNameRange.Value
For i = 1 To UBound(dataArr, 1)
Debug.Print dataArr(i, 1)
Next
End Sub