Using a formula in a variable - excel

I have the following formula:
Range("ZZ1").Formula = "=SUMPRODUCT(--(A3:A" & LastRow & "<>""""))"
Now I wish I could use it directly to get the value without first putting it on my sheet.
Is there a way to get it inside a variable directly as below?
Dim x as long
x = "=SUMPRODUCT(--(A3:A" & LastRow & "<>""""))"

You can use Evaluate like this:
Dim x as long
x = Application.Evaluate("SUMPRODUCT(--(A3:A" & LastRow & "<>""""))")
This will evaluate in the context of the active sheet. You can also use the Worksheet.Evaluate method to evaluate in the context of a specific sheet.
One caveat: the formula string cannot be longer than 255 characters, but that does not appear to be an issue here.

You can use Application.CountIf:
x=Application.Countif(Range("A3:A" & LastRow),"<>"))

Related

Evaluate function giving error 2029 using Excel VBA

Evaluate is throwing error 2029 (#NAME).
The project is using Census procedures to allocate seats in the House of Representatives for any given number of house members (currently 435). There are a number of proposals to expand the size of the House. I'm investigating budget and economic implications.
My workbook has a sheet named PVC. I'm trying to find the maximum value in column E (number of seats allocated to a given state) for a value in column C (two-letter state abbreviations).
I have removed quite a few lines.
I have experimented with a user-defined function MaxIf().
Sub CountSeatsEval()
Dim lNoSeats, lG2, lastrow, lStateRow, lStateSeats, lStateNo As Long
Dim sFileName, sPathName, sFunction, sSearchValue, sSearchState As String
Dim sStateAbbr, vStateSeats As Variant
Dim wsSource, wsTarget As Worksheet
Dim rMaxRange, rSearchValue, rSearchState As Range
Dim rLookup1 As Range
Set wsSource = ThisWorkbook.Worksheets("PVC")
'Following line is to make life easy temporarily
Set wsTarget = ThisWorkbook.Worksheets("PVC")
lNoSeats = wsSource.Range("G2").Value
...
'Copy and paste G2 to replace formula with value
wsTarget.Range("G2").Copy
wsTarget.Range("G2").PasteSpecial (xlPasteValues)
lastrow = wsTarget.Cells(Rows.Count, 6).End(xlUp).Row
...
sSearchValue = "'PVC'!E2:$E$" & lastrow
sSearchState = "'PVC'!$C$6"
...
sStateAbbr = "CA"
lStateRow = 6
vStateSeats = Evaluate("IF((MAXIFS(sSearchValue, sSearchState, sSearchState))>0,(MAXIFS(sSearchValue, sSearchState, sSearchState)),1)")
End Sub
sSearchValue and sSearchState are VBA local variables:
Dim sFileName, sPathName, sFunction, sSearchValue, sSearchState As String
Note that this statement declares sSearchState as a String, and then leaves all other 4 variables without a declared type, making them implicit Variant variables (see VariableTypeNotDeclared Rubberduck inspection details).
Being local VBA variables, they live in the VBA runtime context, and Excel doesn't have the slightest idea about their existence - so you get a #NAME? error:
In Excel you get a #NAME? error whenever you try to evaluate a formula that contains a name that Excel cannot resolve in the current context.
So you need to have VBA evaluate the variables' values before you send the resulting expression over to Excel's calculation engine; you can do this by splitting up the string and using the concatenation operator (&):
vStateSeats = wsTarget.Evaluate("IF((MAXIFS(" & sSearchValue & "," & sSearchState & "," & sSearchState & "))>0,(MAXIFS(" & sSearchValue & "," & sSearchState & "," & sSearchState & ")),1)")
Unqualified, Evaluate will invoke [_Global].Evaluate, which is essentially Application.Evaluate, which may or may not produce the desired results - by qualifying it with a specific Worksheet object, the formula evaluates in the context of that worksheet.

Is there a way to pass a string into the Average function?

I have a worksheet containing a column for the velocity of a vehicle, and I want to take specific ranges from that column (ranges where a turn occurs) and calculate the average speed of all turns combined.
I already have the turn ranges in two arrays, one for the turn starts and one for the turn ends. The code I wrote for this purpose looks like this:
Dim strTurnAvg As String
Dim k As Long
strTurnAvg = ""
For k = LBound(TurnStarts) To UBound(TurnStarts)
If TurnStarts(k) <> TurnEnds(k) Then 'the code for detecting turns rarely messes up and takes the same cell as the start and end of a turn. This is used to ignore such instances
If strTurnAvg = "" Then strTurnAvg = "Range(" & TurnStarts(k) & ":" & TurnEnds(k) & ").Value" Else strTurnAvg = strTurnAvg & ", Range(" & TurnStarts(k) & ":" & TurnEnds(k) & ").Value"
End If
Next
Dim result As Double
result = Application.WorksheetFunction.Average(strTurnAvg) '<- This results in a Run-time error '1004', Unable to get the Average property of the WorksheetFunction class
I tried manually putting the strTurnAvg result into an Average command, and everything worked perfectly fine, but when I try to pass it using the variable, it gives me the runtime error.
Is there a way to achieve this process in another way, or am I doing something wrong?
Try the following:
Dim TurnAvg As Range
Dim k As Long
For k = LBound(TurnStarts) To UBound(TurnStarts)
If TurnStarts(k) <> TurnEnds(k) Then 'the code for detecting turns rarely messes up and takes the same cell as the start and end of a turn. This is used to ignore such instances
If TurnAvg Is Nothing Then
Set TurnAvg = Range(TurnStarts(k), TurnEnds(k))
Else
Set TurnAvg = Union(TurnAvg, Range(TurnStarts(k), TurnEnds(k)))
End If
End If
Next
Dim Result As Double
Result = Application.WorksheetFunction.Average(TurnAvg)
It collects all the ranges using Union into TurnAvg. So you work with the actual ranges and the data in them. You cannot work with strings because you can only calculate with numbers but not with text. The Average functions needs numbers to calculate.
You might want to specify in which workbook/worksheet your ranges are like
ThisWorkbook.Worksheets("Sheet1").Range(TurnStarts(k), TurnEnds(k))
Otherwise VBA might pick the wrong workbook or wrong worksheet.

Wrong number of arguments for search

I am trying to create a VBA macro to automatically label each record in Sheet1 with the correct category based on Sheet2. However, I am getting this error:
Run-time Error '1004': Invalid number of arguments.
When I debug, it seems to point to the line of code noted below.
The codes are as follow in a module tab:
Sub X()
Dim i As Long
Dim r As Long
Dim s As Variant
For i = 1 To Worksheets("Sheet1").Rows.Count
Dim arr() As String
For r = 1 To Worksheets("Sheet2").Rows.Count
' the next line is where i get the error
If Application.IsNumber(Application.Search("Sheet2!A$" & i & ",Sheet1!A" & r)) Then
ReDim Preserve arr(i)
arr(i) = Worksheets("Sheet2").Cells(r, 2)
End If
Next r
For Each s In arr()
Dim b As Long
b = Application.Match(s & ",A1:M1")
Worksheets("Sheet1").Cells(r - 1, b).Value = "Y"
Next s
Erase arr()
Next i
End Sub
Sheet1 shows the special requests to be tagged/labelled with Y in the preceding columns
Sheet2 containing the primary keywords to search for and label the text in Sheet1 with Y if it is found
If you use Application.SomeFunction you should use the proper qualifier WorksheetFunction so you get the intellisense for the required parameters / arguments.
E.g typing Application.WorksheetFunction.Search( instead of Application.Search( will show that you need two string arguments in your Search() function, and you only provide one - but the one you provide does have a comma in it so I suspect you're joining the two arguments together in to one string by mistake.
You could try
("Sheet2!A$" & i, "Sheet1!A" & r)
In VBA this will become (Sheet2.Range("A1"), Sheet1.Range("A9"))
Instead of
("Sheet2!A$" & i & ",Sheet1!A" & r)
Which would resolve to ("Sheet2!A1,Sheet1!A9")
Note the difference - the latter is a single string which is trying to pass to Search() and the first is two separate Range arguments separated by a comma.
Just looking at the line you hightlighted.
If Application.IsNumber(Application.Search("Sheet2!A$" & i & ",Sheet1!A" & r)) Then
It appears:
Application.Search("Sheet2!A$" & i & ",Sheet1!A" & r)
requires two inputs. See link below
expression.Search (Arg1, Arg2, Arg3)
But, I could be wrong.
So the easiest way to debug would be to split up that line and see what is causing the error.
(1) Pull out this part of that line:
Application.Search("Sheet2!A$" & i & ",Sheet1!A" & r)
(2) Does that work? Does it return an argument that makes sense?
If not, fix that line. If so, move on to just the part below with a hardcoded input in the format from part 1 above. From there you can isolate which part of the line is giving you issues and verify each function is getting the right format input.
Application.IsNumber()

Variable String in Formula R1C1

I am trying to create a formula using R1C1 format that will change based on a string containing a variable. I have tried creating the string and inputting it in the formula, as well as creating the string in the formula and none seems to work. Below is my code:
Dim NewXX As Integer
Dim NewXX1 As Integer
Dim CE As Integer
Dim PrevCE As Integer
Dim CEText As String
CE = Cells(NewXX - 1, 1).Value + 1
CEText = "=" & CE
ActiveCell.FormulaR1C1 = _
"=SUMIFS(R[-209]C8:R[1]C8,R[-209]C1:R[1]C1,CEText,R[-209]C2:R[1]C2,""<>Summary"")*(1+R1C16)"
CEText is the variable that will change every time the macro is run. A few things I have tried:
CEText
""CEText"",
'"&CEText&"',
"CEText",
""="""&CE&",
""=""CE,
All of these trials either give me an 'Expected: end of statement' error, or the formula displayed in the cells matches the text (not value) found in the code.
Any help would be greatly appreciated! I am fairly new to VBA and am always up for learning a better way to do things!
Thanks!
CEText is not need when you are equating and since CE is a number, we only need to worry about removing from formula string and concatenating:
ActiveCell.FormulaR1C1 = _
"=SUMIFS(R[-209]C8:R[1]C8,R[-209]C1:R[1]C1," & CE & ",R[-209]C2:R[1]C2,""<>Summary"")*(1+R1C16)"
If you want CEText then we do the extra quotes in the formula:
ActiveCell.FormulaR1C1 = _
"=SUMIFS(R[-209]C8:R[1]C8,R[-209]C1:R[1]C1,""" & CEText & """,R[-209]C2:R[1]C2,""<>Summary"")*(1+R1C16)"
The main issue is that any vba variable must be outside the quotes and concatenated with &

VB syntax error for concatenate and evaluate

I am trying to write a VB script that concatenates data together into a url string and then I want it to copy down into all the rows for that column. I've got the fill down code working okay but when I try to add the concatenate I keep getting a syntax error so I'm not sure what I'm doing wrong. I have tried two versions and they both give me syntax errors on the final line of script (right side):
Script Version 1:
Sub SetSurveyLink()
' SetSurveyLink Macro
Dim lngLastRow As Long
lngLastRow = Cells(Rows.Count, "A").End(xlUp).Row
Range("C3:C" & lngLastRow).Value = EVALUATE("https://domainname.com/survey/?PartName=" & 'Client List'!B1 & "&ClientID="&B2)
End Sub
Script Version 2:
Sub SetSurveyLink()
' SetSurveyLink Macro
Dim lngLastRow As Long
lngLastRow = Cells(Rows.Count, "A").End(xlUp).Row
Range("C3:C" & lngLastRow).Value = CONCATENATE("https://domainname.com/survey/?PartName=",'Client List'!B1,"&ClientID=",B2)
End Sub
The 'concatenate' string gives me the correct value when used in a cell (i.e. not as part of a script) but I just can't get it to work in the script. See anything that I'm missing in my syntax?
THANK YOU!
Any double-quote marks within a string need to be escaped to be double double-quote marks so, if
"https://domainname.com/survey/?PartName=" & 'Client List'!B1 & "&ClientID="&B2
worked within Excel, it becomes
""https://domainname.com/survey/?PartName="" & 'Client List'!B1 & ""&ClientID=""&B2
and then you need to enclose that within double-quote marks to make it a string literal within VBA, i.e.
"""https://domainname.com/survey/?PartName="" & 'Client List'!B1 & ""&ClientID=""&B2"

Resources