【问题标题】:VBA 1004 error - Unable to set the FormulaArray property of the Range classVBA 1004 错误 - 无法设置 Range 类的 FormulaArray 属性
【发布时间】:2015-12-29 11:06:35
【问题描述】:

我正在使用 VBA 将以下 INDEX MATCH 公式插入到一组单元格中。

        cell2.FormulaArray = _
"=INDEX('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!AK:AK, _ 
    MATCH(1,('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!$A:$A = A " & value & ")* _
('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!$B:$B=""Total""),0))*1000"

运行时遇到错误 1004 -“无法设置 Range 类的 FormulaArray 属性”

我相当肯定它与引用当前工作簿之外的工作簿有关,因为当我在同一个工作簿中进行索引匹配时它工作正常。

公式的精简版(为了阅读清晰)如下 -

=INDEX(Sheet2!AK:AK, MATCH(1,(Sheet2!A:A = A5)*(Sheet2!B:B="Total"),0))

然后在vba中-

cell2.FormulaArray = "=INDEX(Sheet2!C:C, MATCH(1,(Sheet2!A:A = A5)*(Sheet2!B:B=""Total""),0))"

【问题讨论】:

  • FormulaArray 限制为 255 个字符。这已经在这里讨论过很多次了。 ;)

标签: vba excel excel-formula


【解决方案1】:

如何使用 VBA 输入超过 255 个字符的FormulaArray

在这种情况下,似乎有一个替代的标准公式符合原始FormulaArray 的要求。但是,可能存在没有替代公式的情况。 对于这些情况,我有以下方法使用 VBA 输入超过 255 个字符的FormulaArray

大多数情况下,FormulaArray 的长度超过 255 个字符是由于它包含的 references 的长度,因为它们可能与长常量数组、具有大名称的外部工作簿有关 (如本例) 或具有大名称的工作表(在本例中也是如此)。该方法包括用较短的字符串替换这些长字符串,但是为了使FormulaArray (替换后) 被接受为FormulaArray,这些较短的字符串也需要代表有效的references .

根据上述情况,至少可能存在三种情况,references 长:

  1. 长常量数组:在这些情况下使用Defined Names,如此处所述

https://support.office.com/en-za/article/Guidelines-and-examples-of-array-formulas-7d94a64e-3ff3-4686-9372-ecfd5caa57c7

  1. Workbooks 大名和
  2. Worksheets 大名

对于情况 2 和 3,同样的方法适用:使用短 references 指向 临时 Worksheet 作为临时替换。

将方法应用于此案例:

原文 FormulaArray:使用变量sFmlArray 保存公式

Dim sFmlArray As String
sFmlArray = "=INDEX('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!AK:AK," & _
    "MATCH(1,('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!$A:$A = A" & bVal & ") * " & _
    "('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!$B:$B=""Total""),0)) * 1000"

我建议使用变量来保存工作簿和工作表的名称,以避免不得不多次编写它们。

Dim sFmlRng as string
sFmlRng = "'[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!"

FormulaArray中的工作簿和工作表的名称替换为对应的变量:

sFmlAry = "=INDEX(" & sFmlRng & "AK:AK," & _
    "MATCH(1,(" & sFmlRng & "$A:$A = A" & bVal & ") * " & _
    "(" & sFmlRng & "$B:$B=""Total""),0)) * 1000"

假设我们想在D7:D10 范围内输入这么长的FormulaArray,让我们将它分配给一个变量

Dim rFmlAry as Range
Set rFmlAry = ActiveSheet.Range("D7:D10")

使用下面的函数添加临时工作表。此函数还提供了 临时 reference 用作FormulaArray 中的替换

Function WshTmp_Add(rFmlAry As Range, sFmlRngTmp As String) As Worksheet
    sFmlRngTmp = "@Tmp"
    With rFmlAry.Worksheet.Parent
        On Error Resume Next
        .Worksheets(sFmlRngTmp).Delete
        On Error GoTo 0
        Set WshTmp_Add = .Worksheets.Add(Before:=.Worksheets(1))
    End With
    WshTmp_Add.Name = sFmlRngTmp
    WshTmp_Add.Tab.Color = 255
    sFmlRngTmp = "'" & sFmlRngTmp & "'!"
    Application.Goto rFmlAry
End Function

FormulaArray 中的长引用替换为较短的引用,并在rFmlAry 范围内输入临时 FormulaArray

sFmlAryTmp = WorksheetFunction.Substitute(sFmlAry, sFmlRng, sFmlRngTmp)
rFmlAry.FormulaArray = sFmlAryTmp

使用FormulaArray,将临时短的references替换为原来的长的

rFmlAry.Replace What:=sFmlRngTmp, Replacement:=sFmlRng, _
    LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
    SearchFormat:=False, ReplaceFormat:=False

最后删除临时 Worksheet

这是整个过程(作为测试,最后添加了几行来验证结果)

Sub FormulaArray_Over255Chr()
Dim rFmlAry As Range, sFmlAry As String, bVal As Byte

Dim WshTmp As Worksheet, sFmlAryTmp As String
Dim sFmlRng As String, sFmlRngTmp As String
Dim blAppDisplayAlerts As Boolean
    blAppDisplayAlerts = Application.DisplayAlerts

    Rem Set Ranges & Values
    bVal = 5
    Set rFmlAry = ActiveSheet.Range("D2:D5")

    Rem Define External Reference Variable
    sFmlRng = "'[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!"

    Rem Define FormulaArray (Original) - with References as Variables
    sFmlAry = "=INDEX(" & sFmlRng & "AK:AK," & _
        "MATCH(1,(" & sFmlRng & "$A:$A = A" & bVal & ") * " & _
        "(" & sFmlRng & "$B:$B=""Total""),0)) * 1000"

    Rem Set Range to Enter FormulaArray
    Set rFmlAry = ActiveSheet.Range("D7:D10")

    Rem Add Temporary Worksheet
    Application.DisplayAlerts = False
    Set WshTmp = WshTmp_Add(rFmlAry, sFmlRngTmp)

    Rem Set Temporary FormulaArray - Replace long references
    sFmlAryTmp = WorksheetFunction.Substitute(sFmlAry, sFmlRng, sFmlRngTmp)

    Rem Enter Temporary FormulaArray
    rFmlAry.FormulaArray = sFmlAryTmp

    Rem Set FormulaArray (Original) - Replace short references in situ
    rFmlAry.Replace What:=sFmlRngTmp, Replacement:=sFmlRng, _
        LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
        SearchFormat:=False, ReplaceFormat:=False

    Rem Delete Temporary Worksheet
    WshTmp.Delete
    Application.DisplayAlerts = blAppDisplayAlerts

' ****************************************************************
' Lines for TESTING - Resulting FormulaArray - REMOVED when final
' ****************************************************************
    Rem Validate FormulaArray
    Debug.Print String(3, vbLf)
    Debug.Print "FormulaArray in Range: "
    Debug.Print rFmlAry.Cells(1).FormulaArray
    Debug.Print "FormulaArray VBA: "
    Debug.Print sFmlAry
    If rFmlAry.Cells(1).FormulaArray = sFmlAry Then
        MsgBox "FormulaArray with +255 entered successfully" & vbLf & _
            vbLf & rFmlAry.Cells(1).FormulaArray
    Else
        MsgBox "Something did not worked!" & vbLf & _
            vbLf & "Review formulas printed in the Immediate Window"
            SendKeys "^g": Stop
    End If
' ****************************************************************

End Sub

【讨论】:

    【解决方案2】:

    根据我的评论,这取决于您可以在 VBA 中使用 FormulaArray 的公式长度的限制。在这里,您可能可以简单地使用非数组版本:

    cell2.Formula = _
    "=LOOKUP(2,1/('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!$A:$A=A" & Value & _
    ")*('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!$B:$B=""Total"")," & _
    "'[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!AK:AK)*1000"
    

    虽然这将返回最后一个匹配项而不是第一个,但如果您有多行匹配您的条件。

    【讨论】:

    • 难以置信的东西。完美运行。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-29
    • 2015-11-22
    相关资源
    最近更新 更多