【问题标题】:Application Calculate from VBA - Ignore Volatile Functions应用程序从 VBA 计算 - 忽略易失性函数
【发布时间】:2019-03-14 11:18:54
【问题描述】:

问题

是否可以有效地从 VBA 模拟 application.calculate 的结果,但忽略 volatile 函数?

详情

定义:非易失性等效项:对于任何易失性工作簿,将非易失性等效项定义为所有具有易失性引用的单元格都已被其原始值替换的工作簿。

定义:非易失性计算差异:假设我们有任何工作簿。现在假设我们采用它的非易失性等价物并对其进行了全面重新计算。取值在非易失性等效项中发生变化的单元格及其值。这些是非易失性计算差异。

问题是这样问的。对于任何包含潜在易失性引用的工作簿,有没有办法有效地应用非易失性差异?效率是这里的关键——这是我们希望忽略 volatile 函数的全部原因——请参见下面的用例。因此,任何不优于完全重新计算的解决方案都是无用的。

用例

我们的工作簿中充斥着INDIRECT 的用法。 INDIRECT 是 Excel 原生的 volatile 函数。工作簿中大约有 300,000 个,其中总共包含大约 150 万个已使用的单元格。我们没有能力改变这些。由于这些INDIRECT 的使用,我们的工作簿需要很长时间才能重新计算。大约 10 秒。所以我们关闭了自动计算,用户会定期点击手动重新计算来刷新数据。

我们的业务用户对此表示满意,但我们正在添加的一些新 VBA 功能可能使用比 10 秒等待更有效的方法。

到目前为止我们所做的尝试

  • Sheet.Calculate - 这在某些情况下很方便。我们确实使用它。但它将所有其他工作表中的数据视为值,而不是公式。因此,如果有任何 zig-zag 引用,这并不能提供完全一致的结果。例如。想象一下来自工作表 A -> 工作表 B -> 工作表 A 的引用:然后需要计算工作表 A,然后是 B,然后是 A。之字形的数量是任意的。这只是一个案例,有两张纸。要解决这个问题,需要从根本上重写 Excel 的整个计算。

【问题讨论】:

    标签: excel vba excel-formula volatile calculation


    【解决方案1】:

    我想到了一件事,但并不理想。也许您可以制作自己的非易失性函数并存储在电子表格中,这将完全符合 INDIRECT 所做的(或您使用的任何公式)。您可以将其称为 INDIRECT2 或其他名称,只需在电子表格中替换它们即可。

    很遗憾,Application.WorksheetFunction.functionName 无法使用此功能,但有一些方法可以绕过它。这只是我的一般想法。

    【讨论】:

    • 对这个想法表示敬意,但我认为它不会为我们服务! INDIRECT 之所以不稳定是有原因的:假设它们所引用的引用通常没有改变是不安全的。通过将 INDIRECT 替换为非易失性等效项,可能无法获取对源数据的某些更改。这是一个我们不能全面承担的风险,尽管它可能适用于我们 300,000 个细胞中的 299,000 个。圣杯是能够有效地告诉 INDIRECT 不要在我们想要的时候计算......但仍然让它们默认计算。
    • 这是一个很好的观点,这就是为什么我说它不理想!我有另一个想法;)您可以创建一个 worksheet_change 事件,其中将影响间接函数的单元格作为目标区域,并且每当它们更改值时,重新计算电子表格。这样计算仍然需要相同的时间,但只有在需要时才会自动刷新数据。通过更多的工作,您可以将其缩小到受影响的单元格,以使其更有效;获取目标单元格的地址,在间接等效函数中找到它,并且只刷新那些受影响的。
    • 这不是一个坏主意。我也有类似的想法。我们可以向非易失性 UDF 添加一个显式参数,该参数会高估所依赖的工作表/范围。这样,如果该工作表/范围上的任何内容发生变化,间接的也会发生变化。它与您的想法相似,但不需要任何事件处理。我们拭目以待。不过,目前我们还没有进行这种重构的空间,所以我想我们会在一段时间内陷入缓慢的重新计算中!谢谢你的 inut。
    • 我喜欢这个,当你实现它时告诉我们,它很有趣,我很想知道它有效且有效!
    【解决方案2】:

    使用与INDIRECT 完成相同工作的非易失性用户定义函数?

    Public Function INDIRECT_NV(ByVal ref_text As String, Optional ByVal a1 As Boolean) As Variant
        'Non-volatile INDIRECT function
        'Does not accept R1C1 notation - the optional is purely for quick replacement
        INDIRECT_NV = CVErr(xlErrRef) 'Defaults to an  error message
        On Error Resume Next 'If the next line fails, just output the error
        Set INDIRECT_NV = Range(ref_text) 'Does the work of INDIRECT, but not for R1C1
    End Function
    

    或者,根据用例,可以使用INDEXMATCH(非易失函数)代替INDIRECT 查询

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-26
      • 2014-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多