【问题标题】:Excel UDF: retrieving value from arbitrary, closed, external workbookExcel UDF:从任意、关闭的外部工作簿中检索值
【发布时间】:2015-05-15 21:27:26
【问题描述】:

我正在寻找一种从任意工作簿返回值的方法(该工作簿在运行 UDF 时也不会打开),根据 UDF 中的计算定义。

伪代码:

Start by calling =someFunc(currentCell) in any cell

Function someFunc(adr As Range)
region_eval = "C" & Range(adr).Row ' where column C contains string entries, all of which have a corresponding sub-dir (see fileReference).
networkLocation = ActiveWorkbook.Path
networkPath = networkLocation & "\Locations\"
fileReference = networkPath & region_eval & "\ProductList.xlsx"

Workbook.Open fileReference readonly
    Perform index/match call against some sheet in this workbook
someFunc = returned value
Close workbook and end function

这是期望的行为。

返回所需值的逻辑是可以的,我已经在一个更简单的公式中尝试过,并且在一个依赖于手动打开文件的 UDF 中:

INDEX(locationlist_$A$5000, MATCH(masterlist_A1, locationlist_$B$5000))  

经过数小时的努力,我发现在设计用于处理非手动打开的工作簿的 UDF 中不能直接使用此功能,而且这是 Microsoft 方面的意图。但我也发现有一种可能的解决方法!

参考:
1.https://stackoverflow.com/a/27844592/4604845
2.http://numbermonger.com/2012/02/11/excel-pull-function-creating-dynamic-links-to-closed-workbooks/

这些解决方案需要硬编码的文件路径,这违背了我的预期用途。

有没有人知道如何通过任意文件路径(例如,包含在与调用 UDF 的单元格相邻的单元格中)实现上述两个链接中的任何一个中所实现的目标?

注意:我尝试在 sub 中进行繁重的工作,只需将 sub 作为 UDF 中的第一行调用,将结果设置为全局 var,并在 sub 完成后将 UDF 返回值设置为相同的 var ,但要么我崩溃并严重烧毁,要么 Excel 识破了我的诡计并否认了它。

编辑:

这是 sub/func 组合。

Option Explicit

Public networkLocation As String, networkPath As String, fileReference As String, c_formula As String
Public sheet_src As Worksheet, sheet As Worksheet, wb_src As Workbook, wb As Workbook
Public region_eval As String, sheetName_src As String, sheetName As String, regionPath As String, fileName As String

Sub findProductStatus(adr As Range)
    networkLocation = ActiveWorkbook.Path
    networkPath = networkLocation & "\Locations\"
    sheetName_src = "Sheet1"
    sheetName = "Sheet1"

    Set wb_src = ThisWorkbook
    Set sheet_src = wb_src.Sheets(sheetName_src)

    region_eval = Range("I" & adr.Row)
    regionPath = networkPath & region_eval
    'fileReference = regionPath & "\ProductList.xlsx"
    fileName = "ProductList.xlsx"
    ChDir regionPath

    Workbooks.Open fileName:=fileName, ReadOnly:=True

    'Set wb = Workbooks.Open(fileName:=ThisWorkbook.Path & "\Locations\Test\ProductList.xlsx", ReadOnly:=True)
    Set wb = Workbooks("ProductList.xlsx")
    Set sheet = wb.Sheets(sheetName)

    c_formula = Application.WorksheetFunction.Index(sheet.Range("$K$2:$K$5000"), Application.WorksheetFunction.Match(sheet_src.Range("A" & adr.Row), sheet.Range("$A$2:$A$5000"), 0))

End Sub


Function getProductStatus(adr As Range) As String

    Call findCourseStatus(adr)
    getCourseStatus = c_formula
    wb.Close

End Function

我还没有针对打开的文件测试 sub/func 组合,但是当所有代码都在函数中并且手动打开有问题的文件时,它可以完美运行。单步执行代码并使用 Debug.Print,我看到即使“Workbooks.Open ...”通过没有任何明显的错误,工作簿实际上并没有被打开,因此,当我们尝试使用工作簿对象时设置工作表,函数/子终止。

【问题讨论】:

  • 我找到了this 的建议,但如果可能的话,我宁愿避免它!
  • 我建议发布您尝试过的sub() 的代码。有人可能会发现错误,或者至少有一些东西可以开始工作。
  • 阅读你的第二个链接,有一个Morefunc add-in的引用(二级主机,好像原来的已经不见了)。如果Gary's answer 不适合您,那可能值得研究。 (我正在为它添加书签以供以后查看...)
  • This approach 允许摆脱 UDF 限制,并通过 UDF 从已关闭的工作簿中获取值。
  • IMO 您最多应该在每个工作表计算事件中打开一个工作簿。考虑通过第一次 UDF 调用打开工作簿,将打开的工作簿保存在全局或静态变量中,并在计算事件结束时关闭。否则,您可能会因 UDF 单元的数量而变慢。

标签: vba excel


【解决方案1】:

这可以通过一个 UDF() 和一个 Event 宏的组合来实现。

要从已关闭的工作簿中检索数据,我们需要做四件事:

  1. 路径
  2. 文件名
  3. 工作表名称
  4. 单元格地址

UDF 唯一能做的就是以非常特定的格式显示这些项目:

Public Function someFunc() As String
    Dim wbPath As String, wbName As String
    Dim wsName As String, CellRef As String
    Dim Ret As String

    wbPath = "C:\TestFolder\"
    wbName = "ABC.xls"
    wsName = "xxx"
    CellRef = "B9"

    someFunc = "'" & wbPath & "[" & wbName & "]" & _
          wsName & "'!" & Range(CellRef).Address(True, True, -4150)
End Function

注意单引号的位置。

然后我们使用 Calculate 事件宏来检测 UDF 的执行并检索数据:

Private Sub Worksheet_Calculate()
  Dim r1 As Range, r2 As Range
  Set r1 = Range("C3")
  Set r2 = Range("C4")
  r2.Value = ExecuteExcel4Macro(r1.Value)
End Sub

Calculate 宏需要知道 UDF 在哪里返回字符串 (C3),它还需要知道将检索到的数据放在哪里 (C4)

【讨论】:

  • 非常好的工作,但是在 UDF 运行之前,文件的完整路径是未知的。文件路径在 UDF 内部确定,基于其相邻单元格的值。例如,如果您在 A2 中运行 UDF,则 B2 将包含字符串“Paris”。 UDF会连接一个字符串,使得路径变成“..\Location\Paris\File.xlsx” 但是UDF在A3中运行时,B3中包含“London”,也就是说不能使用之前的文件路径。
  • 我相信 Gary 是在建议您使用 UDF() 构建完整路径并将其放入已知单元格中,然后使用 On_calculate 事件实际从已关闭的数据中获取数据工作簿。或者反之亦然...
  • 实际上,Gary 的回答看起来与this 非常相似,这是从您链接的 SO 问题中链接的。我还没有完全阅读它,但它似乎对解决方案有更深入的描述。
  • 我确实也读过那篇文章,但我不明白它应该如何动态获取文件路径。看起来您必须在函数运行之前提供文件路径?或者这个概念有什么让我完全无法理解的东西?
  • 我相信目标是构建文件路径,可能使用单元格连接,然后使用 on_change 事件来触发你的 UDF。也许加里会回来帮助澄清。我还没有完全阅读这篇文章或他的建议,无法完全理解它......
猜你喜欢
  • 1970-01-01
  • 2015-05-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-25
相关资源
最近更新 更多