PAYATHON 2026

如何在 VBA 中可靠刷新 Power Query 并避免 ID 数据混杂?

数据小陈

结论

要让报表读取当前 ID 的数据,应等该 ID 刷新完成后再复制报表。对于已加载到工作表表格的 Power Query 结果,可以调用对应 QueryTable 的 Refresh BackgroundQuery:=False,让 VBA 等待刷新完成后再处理下一个 ID。

RefreshAll 会刷新工作簿中的多个连接和查询。将连接的 BackgroundQuery 设为 False,或调用 Application.CalculateUntilAsyncQueriesDone,都不一定能保证报表循环中的查询按预期逐个完成。具体行为取决于查询的加载方式、连接和依赖关系。

按 ID 顺序刷新

下面的代码示意了执行顺序。请将 ID 的设置方式、输出工作表和表名替换为实际名称:

Sub BuildReports()
    Dim ws As Worksheet
    Dim lo As ListObject
    Dim id As Variant

    Set ws = ThisWorkbook.Worksheets("Projects")
    Set lo = ws.ListObjects("Projects")

    For Each id In Array("Main ID 示例", "Sub ID 示例")
        ' 在这里把当前 ID 写入 Power Query 使用的参数或输入单元格。
        ' 例如:ThisWorkbook.Worksheets("Parameters").Range("A1").Value = id

        ' 等待 Projects 对应的查询表刷新完成。
        lo.QueryTable.Refresh BackgroundQuery:=False

        ' 如果报表还依赖工作表公式,在读取或复制前重新计算。
        Application.Calculate

        ' 在这里读取当前 ID 对应的数据并生成或复制报表。
    Next id
End Sub

如果查询从参数表或输入单元格读取 ID,应先写入当前 ID,再刷新输出表。查询刷新完成后,再复制数据或切换到下一个 ID。如果报表依赖其他 Power Query 输出,也应先按依赖关系刷新上游查询,再刷新报表所用的表。

检查查询是否刷新成功

QueryTable.Refresh 会返回布尔值,可以据此检查刷新是否成功:

Dim refreshed As Boolean

refreshed = lo.QueryTable.Refresh(BackgroundQuery:=False)
If Not refreshed Then
    Err.Raise vbObjectError + 1000, "BuildReports", _
              "Projects 查询未能完成刷新。"
End If

对于加载到工作表表格的查询,优先直接刷新对应的 QueryTable。如果只对整个工作簿调用 RefreshAll,就更难确定某个 ID 对应的数据何时可以复制。

关于已尝试的方法

你给出的代码先设置了 OLEDB 连接的 BackgroundQuery,再调用 wbMain.RefreshAll 和 Application.CalculateUntilAsyncQueriesDone;另一个片段则直接刷新 Projects 表。前一种做法涉及多个连接,仅凭调用顺序无法确认每张报表都已取得当前 ID 的数据。后一种做法适用于查询确实加载到 Projects 表的情况,但仍要先更新 ID,并在刷新完成后再复制数据。

用 Timer 固定等待 20 秒无法确认查询是否已经完成。查询可能更快,也可能更慢。应以同步刷新或实际的刷新状态为准,不要假设固定等待时间足够。

注意事项

  • 如果 Projects 不是查询结果实际加载到的表,刷新它不会更新所需的输出。请确认 ListObjects("Projects") 对应的是目标查询表。
  • 如果某个 ID 的报表仍读到上一个 ID 的数据,请检查 ID 参数的更新时间、查询引用的单元格或参数,以及是否有其他宏步骤在刷新前读取或复制结果。
  • 如果查询输出到数据模型、外部连接或其他加载目标,刷新方式可能与工作表 QueryTable 不同,需根据实际加载目标逐项确认。
  • 如果同步刷新后生成的报表仍不完整,请检查查询本身的筛选条件,以及 Main ID、Sub ID 的来源。现有信息不足以判断缺少的 Sub ID 是由刷新时序还是查询逻辑导致的。

备注:内容仅供参考。