Ошибка VBA 1004 - невозможно установить свойство FormulaArray класса Range
Я вставляю следующую формулу INDEX MATCH в набор ячеек, используя VBA.
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 - "Невозможно установить свойство FormulaArray класса Range"
Я вполне уверен, что это как-то связано со ссылкой на рабочую книгу вне текущей, так как она прекрасно работает, когда я ИНДЕКСИРУЕМ МАТЧ внутри той же книги.
Сокращенный вариант формулы (для ясности чтения) следующий:
=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 ответа
Согласно моему комментарию, это сводится к ограничению длины формулы, которую вы можете использовать в 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"
хотя это вернет последний соответствующий элемент, а не первый, если у вас есть несколько строк, соответствующих вашим критериям.
Как войти FormulaArray
более 255 символов, использующих VBA
Похоже, что в этом случае была альтернативная стандартная формула, которая соответствовала требованиям оригинала FormulaArray
, Однако могут быть случаи, для которых нет альтернативной формулы. Для этих случаев у меня есть следующий метод ввода FormulaArray
с более чем 255 символов, использующих VBA.
Большую часть времени, когда FormulaArray
длиннее 255 символов из-за длины references
он содержит, как они могут относиться к длинным постоянным массивам, внешние рабочие книги с большими именами (как в этом случае) или рабочие таблицы с большими именами (также в этом случае). Метод заключается в замене этих длинных строк на более короткие, однако для FormulaArray
(после замены) быть принятым как FormulaArray
эти короткие строки должны также представлять действительные references
,
Согласно вышеизложенному, может быть, по крайней мере, три ситуации с references
:
- Длинные постоянные массивы: в этих случаях используйте
Defined Names
как описано здесь
Workbooks
с большими именами и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"
Предполагая, что мы хотим войти так долго 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
Окончательно удали временный 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