VBA 1004错误 - 无法设置Range类的FormulaArray属性

时间:2015-10-01 11:45:44

标签: vba excel-vba excel-formula excel

我使用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 MATCH时工作正常。

公式的浓缩版本(为了清晰起见)如下 -

=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))"

2 个答案:

答案 0 :(得分:2)

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

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

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

根据上述情况,至少有三种情况可能有references

  1. 长常数数组:在这些情况下,使用此处所述的Defined Names
  2. https://support.office.com/en-za/article/Guidelines-and-examples-of-array-formulas-7d94a64e-3ff3-4686-9372-ecfd5caa57c7

    1. Workbooks名称较大且
    2. Worksheets名字很大
    3. 对于案例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"
      

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

      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中将长引用替换为较短引用,并在FormulaArray范围内输入临时 rFmlAry

      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
      

      最后删除 temporary 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
      

答案 1 :(得分:1)

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

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"

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