简体   繁体   中英

How do I reference a cell using variables? Seemingly “correct” object range returns error 1004 VBA

I am having a problem where no matter how I try to refer to a cell I get run-time error 1004. I have tried referring to it in many way, but every time I try to place the formula in the cells I get stuck.

Sub LoopTest1(ByRef wbOracle As Workbook, ByRef wbReference As Workbook)

    Dim wsOracle As Worksheet
    Set wsOracle = wbOracle.Worksheets(1)
    Dim wsReference As Worksheet
    Set wsReference = wbReference.Worksheets(1)
    Dim ReferenceCell As Range 'will be used for Offset when I get to writing the looping part
    Set ReferenceCell = wsReference.Range("E16")
    Dim formulaText As String
    'Formula below searches for a match on 3 criteria and if there is a match it will write "materials supplied" granted column 9 is >= wsOracle quantity.
   formulaText = "={IF(INDEX('[" & wbReference.FullName & "]Worksheets(1)'!$A$2000:$M$2000,MATCH('[" & wbOracle.FullName & "]Worksheets(1)'!$E16&$I16&$J16,'[" & wbReference.FullName & "]Worksheets(1)'!$D:$D&'[" & wbReference.Name & "]Worksheets(1)'!$E:$E&'[" & wbReference.Name & "]Worksheets(1)'!$F:$F,0),9)>=$M16,""materials supplied"","""")}"
    wsOracle.Range("C16").Formula = formulaText 'Problem line

End Sub

I have tried everything I can think of, even getting quite messy sometimes. I have tried activating the cell which I didn't get an error for. I have tried defining it as a variable, I have tried selecting it. I also tried cleaning up my formula and still no dice. I am just super confusted why I keep getting an error because to me it looks correct .

Try defining formulaText as follows...

formulaText = "=IF(INDEX('[" & wbReference.Name & "]" & wsReference.Name & "'!$A$2000:$M$2000,MATCH('[" & wbOracle.Name & "]" & wsOracle.Name & "'!$E16&$I16&$J16,'[" & wbReference.Name & "]" & wsReference.Name & "'!$D:$D&'[" & wbReference.Name & "]" & wsReference.Name & "'!$E:$E&'[" & wbReference.Name & "]" & wsReference.Name & "'!$F:$F,0),9)>=$M16,""materials supplied"","""")"

Then, since you have an array formula, use FormulaArray instead of Formula...

wsOracle.Range("C16").FormulaArray = formulaText

EDIT

To workaround the character limit, try the following instead...

Sub LoopTest1(ByRef wbOracle As Workbook, ByRef wbReference As Workbook)

    Dim wsOracle As Worksheet
    Set wsOracle = wbOracle.Worksheets(1)

    Dim wsReference As Worksheet
    Set wsReference = wbReference.Worksheets(1)

    Dim ReferenceCell As Range 'will be used for Offset when I get to writing the looping part
    Set ReferenceCell = wsReference.Range("E16")

    Dim formulaPart1 As String
    Dim formulaPart2 As String
    Dim formulaPart3 As String

    formulaPart1 = "'[" & wbReference.Name & "]" & wsReference.Name & "'!$A$2000:$M$2000"
    formulaPart2 = "'[" & wbOracle.Name & "]" & wsOracle.Name & "'!$E16&$I16&$J16"
    formulaPart3 = "'[" & wbReference.Name & "]" & wsReference.Name & "'!$D:$D&'[" & wbReference.Name & "]" & wsReference.Name & "'!$E:$E&'[" & wbReference.Name & "]" & wsReference.Name & "'!$F:$F"

    With wsOracle.Range("C16")
        .FormulaArray = "=IF(INDEX(X_X_X,MATCH(Y_Y_Y,Z_Z_Z,0),9)>=$M16,""materials supplied"","""")"
        .Replace "X_X_X", formulaPart1
        .Replace "Y_Y_Y", formulaPart2
        .Replace "Z_Z_Z", formulaPart3
    End With

End Sub

Indeed, the formula should be a .FormulaArray and something like this works quite ok, as mentioned by @Domenic :

`formulaText = "=IF(INDEX(Tabelle1!$A$2000:$M$2000,MATCH(Tabelle1!$E16&$I16&$J16,Tabelle1!$D:$D&Tabelle1!$E:$E&Tabelle1!$F:$F,0),9)>=$M16,""materials supplied"","""")"`

Anyway, this is a VBA case, where some Test driven development practices would really be helpful, in order to be able to do it yourself. What is the idea of testing? With one sentence, you keep on writing code, until your code does not match the expected values.

So, it is obvious that you are able to write the formula yourself in Excel, without using VBA. You want to use VBA for a reason (and the reason is that it is a great programming language). Thus, you write the formula in Excel in Cell C15 and you keep on working, until you do not get the same formula with VBA in C16 . The test could look like this, thus displaying the differences in the two formulas:

Sub FirstTest()
    With Worksheets(1)
        Debug.Print .Cells(16, "C").Formula = .Cells(15, "C").Formula
        Debug.Print .Cells(16, "C").Formula
        Debug.Print .Cells(15, "C").Formula
    End With
End Sub

If you run the code now, without writing anything, it would return False and the difference of the two cells. So, in VBA, you can start by selecting the already working formula and run the following code:

Public Sub PrintMeUsefulFormula()

    Dim strFormula  As String
    Dim strParenth  As String

    strParenth = """"

    strFormula = Selection.Formula
    strFormula = Replace(strFormula, """", """""")

    strFormula = strParenth & strFormula & strParenth
    Debug.Print strFormula

End Sub

Then see what you are getting in the immediate window Ctrl + G and replace it exactly on the place of the formula. It looks like this (in German Excel):

"=IF(INDEX(Tabelle1!$A$2000:$M$2000,MATCH(Tabelle1!$E16&$I16&$J16,Tabelle1!$D:$D&Tabelle1!$E:$E&Tabelle1!$F:$F,0),9)>=$M16,""materials supplied"","""")"

Now, the fun part starts - you already have a working code, which passes the tests - in Excel the worksheets names are precoded, thus it is ok. However , you need to make the formulas "flexible" with variables for worksheets and workbooks. This is where the tests are really valuable. You can start replacing within the formula string and make sure that it would pass the tests until the end. If something fails, you can always revert to the last change and keep on trying. Give it a try :)

Sub LoopTest1(ByRef wbOracle As Workbook, ByRef wbReference As Workbook)

    Dim wsOracle As Worksheet, wsReference as Worksheet
    Dim wref as String, oref as String, cref(1 To 6) As String

    Set wsOracle = wbOracle.Worksheets(1)
    Set wsReference = wbReference.Worksheets(1)
    wref = "'" & wbReference.Path & "\[" & wbReference.Name & "]" & wsReference.Name & "'!"
    oref = "'" & wbOracle.Path & "\[" & wbOracle.Name & "]" & wsOracle.Name & "'!"
    cref(1) = wref & "$A$2000:$M$2000" : cref(2) = oref & "$E16&$I16&$J16"
    cref(3) = wref & "$D:$D" : cref(4) = wref & "$E:$E"
    cref(5) = wref & "$F:$F" : cref(6) = "$M16"

    With wsOracle.Range("C16")
        .FormulaArray = "=IF(INDEX(CR1, MATCH(CR2, CR3&CR4&CR5, 0), 9) >= CR6, ""materials supplied"","""")"
        .Replace "CR1", cref(1)
        .Replace "CR2", cref(2)
        .Replace "CR3", cref(3)
        .Replace "CR4", cref(4)
        .Replace "CR5", cref(5)
        .Replace "CR6", cref(6)
    End With

End Sub

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM