实现相互依赖的Excel Power Query同步后台查询

问题描述 投票:0回答:1

我在 Excel Power Query (PQ) 中有 3 个查询,其中 1 个是外部查询,另外 2 个是从中派生的。我希望首先运行外部查询,然后依次运行其他查询。我遇到的困难是在查询完成后应用 VBA 代码,每个查询都同步完成并作为后台查询以防止 Excel 冻结。 VBA 的原因(如下所述)可能可以通过其他方式解决,因此我很乐意考虑替代方案。

查询有一些返回文本 =(公式) 的列(通过 PQ 中的 M)。我发现没有办法自动将文本作为公式返回,并且 PQ 在使用公式定义自定义列方面存在限制(例如,不允许使用 Excel 函数)。 VBA 代码用于控制查询的顺序(例如查询 1 完成后,触发事件以触发查询 2 等)并执行 .Formula = .Formula 来解决公式问题。

尝试过的解决方案以及失败原因:

    仅当您将查询添加到数据模型时,才会引发 Worksheet_TableUpdate() 事件。如果添加到数据模型,这将禁用作为后台查询选项运行。
  1. 为了克服数据模型限制,我尝试了 Worksheet_Change() 事件,但该事件引发得太早(很可能是在填充数据之前创建表维度时),因此查询 2 和 3 在查询 1 完成之前发生,导致意外结果,因为它们具有相互依赖的公式。
  2. 使用
Do Until OLEDBConnection.Refreshing = False DoEvents Loop
控制一个查询何时在下一个查询启动之前完成,有一个 Excel 错误,可能与 DoEvents 相关,该错误会阻止循环退出,除非我中断执行并单步执行/再次关闭它

  1. 使用 QueryTable 对象及其事件是一个问题,因为外部查询返回 XML,该 XML 由 PQ 很好地隐式转换并由 OLEDBConnection 对象控制。 QueryTable(据我所知并经过测试)根本不能很好地处理 XML。

  2. 尝试使用 Windows API 来替代 Chat GPT 提供的 DoEvents(我知道这很危险),但没有取得任何进展。这并不是说不可能如此高兴地考虑。

因此,从根本上讲,如果您可以提供一种解决方案,允许同步后台相互依赖的查询,其输出部分包含 Excel 公式,并且表的列中包含本机 Excel 函数,那么应该可以解决该问题。

excel xml powerquery synchronous m
1个回答
0
投票
我做的一件事是拥有一个如下所示的模块:

Option Explicit Dim sheetsToWatch as Collection Dim delay as Double 'A button to kick it all off should call this subroutine Sub ButtonRefresh_Click() Application.DisplayAlerts = False ActiveWorkbook.queries.FastCombine = True ActiveWorkbook.RefreshAll DoStuffWhenRefreshCompletes End Sub 'Set sheetsToWatch and starts watching them Sub DoStuffWhenRefreshCompletes() Dim sht as Worksheet Set sheetsToWatch = New Collection For Each sht In ActiveWorkbook.Sheets If (code to determine if this is a sheet to watch) Then sheetsToWatch.Add Sgt End If Next sht delay = TimeValue("00:00:03") DoStuffWhenSheetsToWatchComplete End Sub Sub DoStuffWhenSheetsToWatchComplete() For i = sheetsToWatch.Count To 1 Step -1 Set sht = sheetsToWatch.Item(i) If not fAnyQueryTablesRefreshing(sht) Then DoStuffNowThatSheetQueriesDone sht sheetsToWatch.Remove i End If Next I If sheetsToWatch.Count <> 0 Then Call Application.OnTime(Now + delay, "DoStuffWhenSheetsToWatchComplete") Else AllDone End If End Sub Function fAnyQueryTablesRefreshing(sht as Worksheet) As Boolean Dim lo as ListObject Dim qt as QueryTable 'queries directly within the sheet For Each qt In sht.QryTables If qt.Refreshing Then fAnyQueryTablesRefreshing = True Exit Function End If Next qt 'queries within ListObjects contained in the sheet For Each lo in sht.ListObjects Set qt = lo.QueryTable If qt.Refreshing Then fAnyQueryTablesRefreshing = True Exit Function End If Next lo fAnyQueryTablesRefreshing = False End Function Sub AllDone() Application.ScreenUpdating = True Set sheetsToWatch = Nothing End Sub Sub DoStuffNowThatSheetQueriesDone(sht As Worksheet) 'code to execute when all queries on a sheet have completed End Sub
显然,我的需求(查询完成后通过 VBA 对每张工作表应用特殊格式)与您的需求不同,因为您不必观看多个查询或按工作表采取后续步骤

,但上面的逻辑对我有用。 您可能想要修改它,以便它只监视单个查询或 ListObject,而不是监视加载到的每个表的所有查询。您可能也不想执行 RefreshAll,而是执行特定的第一个查询。

© www.soinside.com 2019 - 2024. All rights reserved.