First of all, I have tried to look at all the other examples of adding a formula using VBA, and I think I have tried to apply all the answers in this code
Sub AddFormulas(SheetName As String)
Dim i As Integer
'Switch worksheet
Set Wksht = ThisWorkbook.Worksheets(SheetName)
Wksht.Activate
Application.Calculation = xlCalculationManual
i = 2
While Not IsEmpty(Cells(i, 1))
Wksht.Cells(i, 18).Formula = "=IFERROR(VLOOKUP(A" & i & ";" & Wksht.Cells(1, 18) & "!$A:$A;1;FALSE);" & Chr(34) & "MISSING" & Chr(34) & ")"
i = i + 1
Wend
Application.Calculation = xlCalculationAutomatic
End Sub
But still, it gives me this anoying error, that I can't interpret
If I change my line to
Wksht.Cells(i, 18) = "'IFERROR(VLOOKUP(A" & i & ";" & Wksht.Cells(1, 18) & "!$A:$A;1;FALSE);" & Chr(34) & "MISSING" & Chr(34) & ")"
Then I get no error, and the correct formula is added, although as a text string
What is wrong, since it would not add what to me looks like a valid formula?
//V
The Formula property requires formulas to be written in English, i.e. English function names (not an issue here) and commas as separators rather than semi-colons.
So your statement should be:
Wksht.Cells(i, 18).Formula = "=IFERROR(VLOOKUP(A" & i & "," & Wksht.Cells(1, 18) & "!$A:$A,1,FALSE)," & Chr(34) & "MISSING" & Chr(34) & ")"
If you don't mind having "portability" issues, you could also use the FormulaLocal property, i.e.
Wksht.Cells(i, 18).FormulaLocal = "=IFERROR(VLOOKUP(A" & i & ";" & Wksht.Cells(1, 18) & "!$A:$A;1;FALSE);" & Chr(34) & "MISSING" & Chr(34) & ")"
Write the formula as it should be in Excel, select it 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
It should print it as it should be.
I believe your code is giving error becouse of this Wksht.Cells(1, 18) part of line in this row Wksht.Cells(i, 18).Formula = "=IFERROR(VLOOKUP(A" & i & ";" & Wksht.Cells(1, 18) & "!$A:$A;1;FALSE);" & Chr(34) & "MISSING" & Chr(34) & ")". Make sure that Wksht.Cells(1, 18) really contains name of worksheet your are trying to address. If this cell is blank, you will receive previously mentioned error.
Related
In VBA I am trying to create a sumifs formula with multiple criteria across different workbooks, but I am struggling on the syntax.
WorkbookRecut.Worksheets("Summary").Activate
Dim CountRows As Long
Dim CountRows2 As Long
CountRows = WorkbookRecut.Worksheets("Summary").Range("I" & WorkbookRecut.Worksheets("Summary").Rows.Count - 1).End(xlUp).Row
CountRows2 = CashBreaksMetricsWorkbookFinal.Worksheets("CSCIG_Cash Breaks Metrics").Range("I" & CashBreaksMetricsWorkbookFinal.Worksheets("CSCIG_Cash Breaks Metrics").Rows.Count - 1).End(xlUp).Row
CashBreaksMetricsWorkbookFinal.Worksheets("CSCIG_Cash Breaks Metrics").Activate
Range("O6").Formula = _
"=Sumifs(" & [WorkbookRecut].Sheets("Summary").Range("I9").Address & ":" & [WorkbookRecut].Sheets("Summary").Range("I" & CountRows).Address _
& "," & [WorkbookRecut].Sheets("Summary").Range("A9").Address & ":" & [WorkbookRecut].Sheets("Summary").Range("A" & CountRows).Address _
& "," & [CashBreaksMetricsWorkbookFinal].Worksheets("CSCIG_Cash Breaks Metrics").Range("K6").Address(Rowabsolute:=False) _
& "," & [WorkbookRecut].Sheets("Summary").Range("D9").Address & ":" & [WorkbookRecut].Sheets("Summary").Range("D" & CountRows).Address _
& "," & [CashBreaksMetricsWorkbookFinal].Worksheets("CSCIG_Cash Breaks Metrics").Range("N6").Address(Rowabsolute:=False) & ")"
CashBreaksMetricsWorkbookFinal.Worksheets("CSCIG_Cash Breaks Metrics").Range("O6:O" & CountRows2).FillDown
Update
I have updated the most recent code. The only pending issue is the workbooks aren't changing, but all else works as I want :)
When creating a formula string to add to a cell you need to take into account where the different ranges are relative to the sheet where you're going to place the formula. Just calling Address() on one of the inputs may not give you what you want.
You can try something like the code below to abstract that part into a separate function:
Sub Tester()
Dim wsSumm As Worksheet, wsCBM As Worksheet
Dim lr As Long, f
Set wsSumm = WorkbookRecut.Worksheets("Summary")
Set wsCBM = CashBreaksMetricsWorkbookFinal.Worksheets("CSCIG_Cash Breaks Metrics")
lr = wsSumm.Cells(Rows.Count, "I").End(xlUp).Row
f = "=SUMIFS(" & RealAddress(wsCBM, wsSumm.Range("I9:I" & lr)) & "," & _
RealAddress(wsCBM, wsSumm.Range("A9:A" & lr)) & ",$K6," & _
RealAddress(wsCBM, wsSumm.Range("D9:D" & lr)) & ",$N6)"
With wsCBM.Range("O9")
.Formula = f
End With
End Sub
'get a range address for `rngRef`,
' suitable for use in a formula on worksheet `ws`
Function RealAddress(ws, rngRef As Range) As String
Dim s As String
If ws.Parent Is rngRef.Worksheet.Parent Then 'same workbooks?
If Not ws Is rngRef.Worksheet Then s = "'" & rngRef.Worksheet.Name & "'!" 'diff. worksheets?
s = s & rngRef.Address(True, True)
Else
s = rngRef.Address(True, True, external:=True) 'different workbooks
End If
RealAddress = s
End Function
For the formula: You're probably looking for the .Address property from each of your Ranges. Something like Range1.Address & ":" & Range2.Address To get an output like $I$9:$I$307.
But for your Ranges, you need to put the CountRows inside the Range input like WorkbookRecut.Sheets("Summary").Range("A" & CountRows) and then add the .Address to it.
I also agree with #TimWilliams that your formula code could benefit greatly in terms of readability by adding some nicknames for your worksheets.
Here is what your code would look like with those 3 things corrected:
Public CashBreaksMetricsWorkbookFinal As Workbook
Public WorkbookRecut As Workbook
Dim SumSh As Worksheet
Set SumSh = WorkbookRecut.Sheets("Summary")
Dim CountRows As Long
CountRows = SumSh.Range("I" & SumSh.Rows.Count - 1).End(xlUp).Row
Dim CSCIG As Worksheet
Set CSCIG = CashBreaksMetricsWorkbookFinal.Worksheets("CSCIG_Cash Breaks Metrics")
CSCIG.Activate
Range("O9").Formula = _
"=Sumifs(" & SumSh.Range("I9") & ":" & SumSh.Range("I" & CountRows).Address _
& "," & SumSh.Range("A9").Address & ":" & SumSh.Range("A" & CountRows).Address _
& "," & CSCIG.Range("K6").Address _
& "," & SumSh.Range("D9").Address & ":" & SumSh.Range("D" & CountRows).Address _
& "," & CSCIG.Range("N6").Address & ")"
CSCIG.Range("O9").FillDown
We were missing .Address(External:=True)
Thanks all for helping me get there (Finally!)
Final Code Below
Public CashBreaksMetricsWorkbookFinal As Workbook
Public WorkbookRecut As Workbook
Dim CountRows As Long
Dim CountRows2 As Long
CountRows = WorkbookRecut.Worksheets("Summary").Range("I" & WorkbookRecut.Worksheets("Summary").Rows.Count - 1).End(xlUp).Row
CountRows2 = CashBreaksMetricsWorkbookFinal.Worksheets("CSCIG_Cash Breaks Metrics").Range("I" & CashBreaksMetricsWorkbookFinal.Worksheets("CSCIG_Cash Breaks Metrics").Rows.Count - 1).End(xlUp).Row
CashBreaksMetricsWorkbookFinal.Worksheets("CSCIG_Cash Breaks Metrics").Activate
Range("O6").Formula = _
"=Sumifs(" & [WorkbookRecut].Sheets("Summary").Range("I9").Address(External:=True) & ":" & [WorkbookRecut].Sheets("Summary").Range("I" & CountRows).Address(External:=True) _
& "," & [WorkbookRecut].Sheets("Summary").Range("A9").Address(External:=True) & ":" & [WorkbookRecut].Sheets("Summary").Range("A" & CountRows).Address(External:=True) _
& "," & [CashBreaksMetricsWorkbookFinal].Worksheets("CSCIG_Cash Breaks Metrics").Range("K6").Address(Rowabsolute:=False) _
& "," & [WorkbookRecut].Sheets("Summary").Range("D9").Address(External:=True) & ":" & [WorkbookRecut].Sheets("Summary").Range("D" & CountRows).Address(External:=True) _
& "," & [CashBreaksMetricsWorkbookFinal].Worksheets("CSCIG_Cash Breaks Metrics").Range("N6").Address(Rowabsolute:=False) & ")"
CashBreaksMetricsWorkbookFinal.Worksheets("CSCIG_Cash Breaks Metrics").Range("O6:O" & CountRows2).FillDown
In the formula, you have to double-quote existing quotes:
Change
Sheets("Summary")
to:
Sheets(""Summary"")
This question already has answers here:
Different languages issue when inserting formula from VBA
(1 answer)
Excel VBA Run-time error 1004 when inserting or value formula into cell
(1 answer)
VBA code string to cell not working - run time error 1004
(1 answer)
Closed 5 years ago.
I have a problem with a formula in VBA. It works in conditional formatting and in excel itself, but I can't use it from VBA level
This is the code:
Range("A1").Formula = "=IF(ISERR(FIND(" & Chr(34) & "-" & Chr(34) & ";" & s_adr_1 & ";2))=FALSE;TRUE;IF(ISERR(FIND(" & Chr(34) & "…" & Chr(34) & ";" & s_adr_1 & ";2))=FALSE;TRUE;IF(ISERR(FIND(" & Chr(34) & ".." & Chr(34) & ";" & s_adr_1 & "))=FALSE;TRUE;IF(ISBLANK(" & s_adr_1 & ");FALSE;IF(AND(IF(ISERR(RIGHT(" & s_adr_1 & ")*1);NOT(ISERR(FIND(" & s_adr_2 & ";" & s_adr_1 & ")));TRUE));FALSE;IF(LEFT(" & s_adr_1 & ")=""#"";FALSE;ISERR(FIND(" & s_adr_2 & ";" & s_adr_1 & "))))))))"
Where s_adr_1 and s_adr_2 are a references to cells so it can look like this as a sample (in B1 there will be my test text, like e.g. "5-15", "15", "5...15"):
Range("A1").Formula = "=IF(ISERR(FIND(" & Chr(34) & "-" & Chr(34) & ";" & "B1" & ";2))=FALSE;TRUE;IF(ISERR(FIND(" & Chr(34) & "…" & Chr(34) & ";" & "B1" & ";2))=FALSE;TRUE;IF(ISERR(FIND(" & Chr(34) & ".." & Chr(34) & ";" & "B1" & "))=FALSE;TRUE;IF(ISBLANK(" & "B1" & ");FALSE;IF(AND(IF(ISERR(RIGHT(" & "B1" & ")*1);NOT(ISERR(FIND(" & "C1" & ";" & "B1" & ")));TRUE));FALSE;IF(LEFT(" & "B1" & ")=""#"";FALSE;ISERR(FIND(" & "C1" & ";" & "B1" & "))))))))"
Expected outcome in A1 would be:
=IF(ISERR(FIND("-";B1;2))=FALSE;TRUE;IF(ISERR(FIND("…";B1;2))=FALSE;TRUE;IF(ISERR(FIND("..";B1))=FALSE;TRUE;IF(ISBLANK(B1);FALSE;IF(AND(IF(ISERR(RIGHT(B1)*1);NOT(ISERR(FIND(C$1;B1)));TRUE));FALSE;IF(LEFT(B1)="#";FALSE;ISERR(FIND(C$1;B1))))))))
It should return TRUE or FALSE.
When I try to run the code I got Error 1004 :(
What is wrong here? Why it works when I paste it in Excel manually?
Assuming that you are using English Excel version, simply use double quotes in the VBA version. Or pretty much do the following:
write the formula in Excel and select the cell, where it is
run this code and mimic the formula, that you get:
-
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
I have numerous cells on a worksheet with the following formula:
=IF(COUNTIF(O7:O9;"Fail");"Fail";"Pass")
I want to replace all the cells with this formula with the following formula:
=IF(COUNTIF(O7:O9;"");"Default";(IF(COUNTIF(O7:O9;"Fail");"Fail";"Pass")))
How can I change them all to the new formula in one swoop? It is a bunch of cells and please notice that all the cells with a formula have different references.
You can just do a ctrl+h and replace the forumulae directly.
This should work
Just select all cells with "those" formulas you mentioned above, If you select any blank cells, or cells with different formulas, it will crash
You can alternatively select a few cells at a time
Sub changeFormulaOfSelectedCells()
Dim rng As Range
Dim rangeInFormula As String
Dim cellFormula As String
For Each rng In Selection
cellFormula = rng.Formula
rangeInFormula = Mid(cellFormula, 13, InStr(cellFormula, ";") - 13)
rng.Formula = "=IF(COUNTIF(" & rangeInFormula & ";" & Chr(34) & Chr(34) & ");" & Chr(34) & "Default" & Chr(34) & ";(IF(COUNTIF(" & rangeInFormula & ";" & Chr(34) & "Fail" & Chr(34) & ");" & Chr(34) & "Fail" & Chr(34) & ";" & Chr(34) & "Pass" & Chr(34) & ")))"
Next rng
End Sub
If you get an error, Just check if I have not missed replacing any , with ;in the above code
This is part of a much larger macro that has multiple instances of Application.OnTime that work just fine.
My issue with this one below is in WaitForPriceVolume() when it gets to the For Each loop and the If is true, it doesn't go back to the procedure WaitForPriceVolume(). It circles back to all the procedures that were called before, effectively just doing the Exit Sub as if the OnTime didn't exist.
When I strip out just the below code and add fixed values for the global variables being used, the Application.OnTime works. It's only when I plug it back into the bigger macro.
Sub BDP_PriceVolume()
Dim lsStartRange As String
Dim lsEndRange As String
Dim lnStartRow As Long
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Set sht = Worksheets("Variables")
' Use gvList
lsStartRange = "C" & gnStartRow
lnStartRow = gnStartRow + UBound(gvList, 2)
lsEndRange = "C" & lnStartRow
sht.Range(lsStartRange & ":" & lsEndRange).Value = _
"=BDP($A" & gnStartRow & "&Variables!$A$2,Variables!$D$2)"
lsStartRange = "D" & gnStartRow
lsEndRange = "D" & lnStartRow
If Worksheets("Variables").Cells(3, 3).Value <> "" Then
sht.Range(lsStartRange & ":" & lsEndRange).Value = _
"=BDH($A" & gnStartRow & "&Variables!$A$2,Variables!$E$3" & "," & _
"Variables!$B$4,Variables!$C$3," & _
Chr(34) & "BarTp=T" & Chr(34) & "," & _
Chr(34) & "BarSz=40" & Chr(34) & "," & _
Chr(34) & "Dir=V" & Chr(34) & "," & _
Chr(34) & "Dts=H" & Chr(34) & "," & _
Chr(34) & "Sort=A" & Chr(34) & "," & _
Chr(34) & "Quote=C" & Chr(34) & "," & _
Chr(34) & "UseDPDF=Y" & Chr(34) & ")"
Else
sht.Range(lsStartRange & ":" & lsEndRange).Value = _
"=BDP($A" & gnStartRow & "&Variables!$A$2,Variables!$E$2)"
End If
sht.Range("C" & gnStartRow & ":" & lsEndRange).Select
Application.Run "RefreshCurrentSelection"
Application.OnTime Now + TimeValue("00:00:03"), "WaitForPriceVolume"
End Sub
Private Sub WaitForPriceVolume()
Dim rng As Range
Set rng = sht.Range("C" & gnStartRow & ":D" & fnLastRow(sht, "A"))
Dim cell As Range
Application.ScreenUpdating = True
For Each cell In rng
If cell.Value = "#N/A Requesting Data..." Then
Application.OnTime Now + TimeValue("00:00:03"), "WaitForPriceVolume"
Exit Sub
End If
Next cell
Call DoneWaitForPriceVolume
End Sub
Own stupidity. All the other instances of OnTime came at the end of the code, so the macro had nothing left to do until the OnTime triggered and I forced everything to circle back to the main macro. I hadn't done that in this case. Problem solved. This haunted me for a week
I am trying to put together one main spreadsheet that pulls from over 100 workbooks containing various data. I haven't been able to figure out how to access a closed Workbook in order to calculate the standard deviation from one of the rows.
Sub RefreshSourceData()
Dim sourceFile, fileName As String, path As String
Dim dispersionRange As Range
path = "U:\SPACE Info\Meeting Materials\Strategy Files\"
fileName = "[" & ActiveCell.EntireRow.Cells(1, 1).Value & ".xls]"
sourceFile = "=" & path & fileName
dispersionRange = "=" & path & fileName & "Account'!R:R"
Range("B" & ActiveCell.Row).Formula = sourceFile & "Summary'!$F$2"
Range("C" & ActiveCell.Row).Formula = sourceFile & "Summary'!$F$3"
Range("D" & ActiveCell.Row).Formula = sourceFile & "Summary'!$B$10"
Range("E" & ActiveCell.Row).Formula = sourceFile & "Summary'!$D$10"
Range("F" & ActiveCell.Row).Formula = WorksheetFunction.StDev(dispersionRange)
End Sub
I have received various errors, right now it is "Object Variable or With Object Variable not set."
I have also tried creating a workbook variable consisting of path & filename, but this hasn't worked either.
These are some best effort suggestions, since I can't test everything (I don't have your data).
For your immediate error, I think you intended dispersionRange to be a String, not a Range.
Also, when adding the formula references, make sure you add single quotes around your sourceFile, e.g.:
Range("B" & ActiveCell.Row).Formula = "'" & sourceFile & "Summary'!$F$2"
Range("C" & ActiveCell.Row).Formula = "'" & sourceFile & "Summary'!$F$3"
Range("D" & ActiveCell.Row).Formula = "'" & sourceFile & "Summary'!$B$10"
Range("E" & ActiveCell.Row).Formula = "'" & sourceFile & "Summary'!$D$10"
^^^^^
Similarly for dispersionRange (notice the missing =):
dispersionRange = "'" & path & fileName & "Account'!R:R"
Finally, the last .Formula (for the "F" column) should be .Value, as StDev returns a Double. In addition, the function StDev doesn't take a range as String but a proper Range object, so try this instead:
Range("F" & ActiveCell.Row).Value = WorksheetFunction.StDev(Range(dispersionRange))
UPDATE
To avoid confusion, I've modified your code and I'm listing it below. Please note this is untested, as I don't have access to your workbook, but it should work.
Sub RefreshSourceData()
Dim sourceFile, fileName As String, path As String
Dim dispersionRange As String
path = "U:\SPACE Info\Meeting Materials\Strategy Files\"
fileName = "[" & ActiveCell.EntireRow.Cells(1, 1).Value & ".xls]"
sourceFile = path & fileName
dispersionRange = "'" & path & fileName & "Account'!R:R"
Range("B" & ActiveCell.Row).Formula = "='" & sourceFile & "Summary'!$F$2"
Range("C" & ActiveCell.Row).Formula = "='" & sourceFile & "Summary'!$F$3"
Range("D" & ActiveCell.Row).Formula = "='" & sourceFile & "Summary'!$B$10"
Range("E" & ActiveCell.Row).Formula = "='" & sourceFile & "Summary'!$D$10"
Range("F" & ActiveCell.Row).Value = WorksheetFunction.StDev(Range(dispersionRange))
End Sub