Aggregate function in VBA Excel - excel

I have table with Product name and Batch No. The product name is selected from a combo box frmmaster.cmbproduct.
Each product has a unique combination for batch number and the last digit of the batch number changes.
Sample table
The next batch number of a particular product is the last batch number +1. I have used aggregate function in excel to find the highest batch number. But the same aggregate function is throwing error in VBA.
Aggregate function for excel is =AGGREGATE(14,4,($B$2:$B$2000 =N12)*$C$2:$C$2000,1) where in N12 I am putting product name. Column B contains product name and column C contains batch number
Dim res As Long
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Database")
With sh
'On Error Resume Next
res = WorksheetFunction.Aggregate(14, 4, ("R2C2:R2000C2" = FrmMaster.CmbProduct.Value) * "R2C3:R2000C3", 1)
MsgBox (res)
End With
The above code is throwing type mismatch error
I have changed the variable to hold value to variant and string but no result.

The reason for the type mismatch error is that the term ("R2C2:R2000C2" = FrmMaster.CmbProduct.Value) * "R2C3:R2000C3" tries multiplying a boolean value (result of ("R2C2:R2000C2" = FrmMaster.CmbProduct.Value)) with the string literal "R2C3:R2000C3". That of course is a type mismatch.
But there are other issues.
The term "R2C2:R2000C2" = FrmMaster.CmbProduct.Value compares the string "R2C2:R2000C2" to the FrmMaster.CmbProduct.Value. This always gets false except FrmMaster.CmbProduct.Value would be "R2C2:R2000C2". And it is not the same as $B$2:$B$2000=N12 in your array formula. There the $B$2:$B$2000 is a range of cell values which each gets compared to value of N12. But this is nothing what VBA is able to do. Even (sh.Range("$B$2:$B$2000") = FrmMaster.CmbProduct.Value) cannot work because this tries comparing an array (sh.Range("$B$2:$B$2000")) to a single value.
So the only way to evaluate an array formula having that kind of array operations in it is using Evaluate. WorksheetFunction cannot help here since it needs the single function parameters evaluated trough VBA first.
Example solving your problem:
Dim res As Long
Dim sh As Worksheet
Dim range1Address As String
Dim range2Address As String
Dim arrayFormula As String
Set sh = ThisWorkbook.Sheets("Database")
With sh
range1Address = .Range("B2:B2000").Address(RowAbsolute:=True, ColumnAbsolute:=True, ReferenceStyle:=xlA1, External:=True)
range2Address = .Range("C2:C2000").Address(RowAbsolute:=True, ColumnAbsolute:=True, ReferenceStyle:=xlA1, External:=True)
arrayFormula = "AGGREGATE(14,4,(" & range1Address & "=""" & FrmMaster.CmbProduct.Value & """)*" & range2Address & ",1)"
res = Evaluate(arrayFormula)
MsgBox res
End With
Getting range1Address and range2Address as external addresses (including workbook name and sheet name) from the ranges makes this independent of the active sheet.

I wonder if the formula below will be of help to you. It will return whatever number it finds associated with the lookup value +1.
=IFERROR(LOOKUP(2,1/($A1:$A$1=A2),$B1:$B$1),0)+1
First, the functionality. The function looks for the last occurrence of A2 above A2 which is in a range starting at absolute $A$1 and ending in relative $A1. The latter will expand as the formula copied down. Same system in column B. If nothing is found and error occurs, and if an error occurs the function returns 0. To the result of this 1 is added.
Now, if you would replace the 0 in the formula (which is the result in case of no precedent) with a number like 2022050 the formula would then return the correct result in the first row of your example and for all subsequent occurrences of "Amoxycillin Capsules 500".
It would return 1 on the line of Paracetamol tablets because there is no precedent. The 1 would stick out and perhaps you have a system by which you can fill in the missing numbers there.
The problem would be the same, regardless of whether you apply VBA or a worksheet function. You need a seed number to base increments on. All considered, the worksheet function looks easier to implement.

Related

XLookup function won't detect an exact match until I place the cell in edit mode and then exit

I am using the XLookup function in Excel 365. I use a VBA script to create an ID number for a row of data and then I place that ID number into a cell.
If I use the XLookup function with Exact Match to locate that ID number and give me some value in a column next to it, I get an N/A.
However, if I manually locate that exact ID number and place the cell in edit mode and then exit the cell without taking any other step to alter the data in any way, the XLookup function returns the correct result.
If I leave the cell in it's initial state but use the Match Mode "-1" to get an exact match or next smaller, it returns the correct result. I don't want to leave it in that mode, because my final function will be two nested Xlookup functions that check one table for the ID and if not there, looks at an alternate table, so I don't want the first function to return a "next smaller" result.
When I generate the ID number in the VBA script, I generate it as the type "Variant" because the ID number is a decimal, such as 210.1. I then simply set that cell's Value to the variant ID number.
Here is a how I place the data into the cell:
Dim myID As Variant
Dim myCell As Variant
Dim myRange As Range
Set myRange = Range(someNamedRange)
myID = GenerateNextID 'This generates a variant in the form of something like 201.1
For Each myCell In myRange
myCell.Value = myID
myID = myID + 0.1
Next myCell
Excel seems to recognize it as a number; at least I seem to be able to do math functions on the ID number and get correct results.
I tried putting the lookup ID number in quotes to see if looking it up as text instead of a number produced a different result, but it didn't change my result.
Why am I getting this result? Is there a way to resolve it without using a different Match Mode?
You have a floating point precision error. The value in E11 is 211.39999999999998 rather than 211.4. Excel corrects the error when you re-enter the cell's value.
Write the value using a line like:
myID = Round(myID + 0.1, 1)

VBA - Excel - How to write a formula in a cell instead of values using list objects

I'm struggling with VBA and couldn't find a solution on internet.
This is what I'm trying to do.
I have an excel file with two sheets
First sheet is an extract from a Database (with many columns, an particulary one called "country"). It is formated as a ListObject
Second sheet is a Calculator that is counting the number of occurence of every country in the other sheet. It is also formated as a list object
For Example at the end I'll get:
France: 10
USA: 25
Italia: 30
I found how to calculate this using the Application.WorksheetFunction.CountIf function.
Now my question is: Is it possible to write the formula in the cell, instead of writing the result ?
The objectif is to generate a sheet filled with formulas, so that when I change things in the Database sheet, then it will automatically recalculate my results.
This is my current code: It works, but I'd like to write a formula in the cell, instead of the result.
It there an easyway to do this ?
Thanks a lof for your help !
Regards,
J.
Dim i As Long
Dim CountryName As Variant
Dim KPI_LO As ListObject
Dim REVIEWEDDATA_LO As ListObject
'This is the list object with the database information
Set REVIEWEDDATA_LO = Worksheets(REVIEWEDDATA_SHEET_NAME).ListObjects(REVIEWEDDATA_LISTOBJECT_NAME)
'This is the list object where I'll store my results
Set KPI_LO = Worksheets(WASPKPI_SHEET_NAME).ListObjects(WASPKPI_LISTOBJECT_NAME)
'loop through each country column in the result sheet
For i = LBound(GetCountriesList) To UBound(GetCountriesList)
'Get the name of the first country to find
CountryName = GetCountriesList(i)
'Count the number of occurence of this country in the column called COL_COUNTRY in the revieweddata List Object (in my database sheet).
'This is what I'm trying to replace. I want to write a formula that do this calculation in the cell, instead of the result.
KPI_LO.ListColumns(CountryName).DataBodyRange.Rows(1) = Application.WorksheetFunction.CountIf(REVIEWEDDATA_LO.ListColumns(COL_COUNTRY).DataBodyRange, CountryName)
Next i
if you want to see the formula in a cell, then you can create a function and then just call that and pass through your values.
For example, create a module:
Function fn_Multiply(x As Double, y As Double) As Double
Dim z As Double
z = x * y
fn_Multiply = z
End Function
And use it in excel as a formula like this:
=fn_Multiply(A2,B2)
enter image description here

Count the number of variables in a formula

I'm trying to reassemble some data that was loss for my office. One thing that could make life exponentially better is the ability to count the number of variables in a formula. For example:
=500+500+500
Ideally, I would like to return "3" in this situation, as there are three "variables" in the above formula. Right now I'm using a formula to pull the exact value from the particular cell, but I'd like to add something that would allow me to also output the number of variables in the formula/calculation.
If the only operator is + then this will get the count:
=LEN(FORMULATEXT(A1))-LEN(SUBSTITUTE(FORMULATEXT(A1),"+",""))+1
Since you may have different operators beside a + sign, you could do something like this in VBA:
Function count_parts(rngFormula As Range) As Integer
'Create an array with all the operators you want to account for
Dim operatorArray As Variant, operator As Variant
operatorArray = Array("+", "-", "/", "*")
'Capture the formula in the cell passed in
Dim strFormIn As String: strFormIn = rngFormula.Formula
Dim strFormOut As String: strFormOut = strFormIn
'Loop through the operators in the array and swap them out
'So the strFormOut is completely rid of them all
For Each operator In operatorArray
strFormOut = Replace(strFormOut, operator, "")
Next
'Count the difference in characters between our starting
'formula and the formula without operators, subtracting 1.
count_parts = Len(strFormIn) - Len(strFormOut) + 1
End Function
If + is the only operator you have to account for, then a much more simple function could be used:
Function count_parts(rngFormula As Range) As Integer
count_parts = UBound(Split(rngFormula.Formula, "+")) + 1
End Function
You can stick either of these in a new module in your VBE and after saving the workbook you can use this formula in a cell like =count_parts(A1)

Excel VBA: Using 2 variables with Match

ws2.Range("D3").Value = Application.WorksheetFunction.Match(variable_i, ws2.Range("A:A"), 0)
ws1 = worksheet 1
ws2 = worksheet 2
On ws1 I have 2 columns of drop down boxes (data validation list)
the selection from the first column of drop down boxes is assigned to the variable "variable_i"
the selection from the second column of drop down boxes is assigned to the variable "variable_p"
It pulls its data from ws2 (the range is all of column a)
It is looking for the selection from the drop down box with the variable "variable_i"... the code works fine, it returns the number row on D3 without any issues
I'm looking for it to return the row number that contains both variables in the 2 columns (variable_i and variable_p)
I've tried the following code:
ws2.Range("D3").Value = Application.WorksheetFunction.Match(variable_i & variable_p, ws2.Range("A:B"), 0)
as I had seen that online, but it doesn't work for me.
The error I get is:
"Run-time error '1004':
Method 'Match' of object 'WorksheetFunction' failed
What would be the best way to have multiple variables be the lookup?
Any help would be much appreciated!
The key for you I believe could be to use EVALUATE() function. Multiple criteria would mean you most likely need an array which EVALUATE will recognize. Also concatenating values and ranges to check for two criteria is definately not the best solution. Imagine cell A1=1 and B1=101. What happens if you concatenate ranges to 1101 and you look for criteria1 10 and 11 instead of 1 and 101?
A simple evaluate example:
Debug.Print Evaluate("MATCH(1,(A1:A6=1)*(B1:B6=""B""),0)")
In my example I have one Long and one String variable, respectively 1 and B. Would I use your named variable variable_i and variable_p I could make a code like:
ws2.Range("D3") = Evaluate("MATCH(1,('Sheet1'!A1:A6=" & variable_i & ")*('Sheet1'!B1:B6=""" & variable_p & """),0)")
Notice the difference of adding a Long or a String variable? That's because to evaluate correctly in VBA there needs to be two quotation marks surrounding a String variable. A number can do without.
Also notice I specified sheet names in the code, you can change that according to your needs

Excel: Searching for multiple terms in a cell and return the found value

I am trying to scan a column and search for terms inside a cell.
Once any of these terms are found, place the found one in another cell.
The terms are in a named range, I call it "namedrangeOfApps" with over 400 rows.
This is what I have now but instead of returning TRUE I want to return the actual value found.
=SUMPRODUCT(--ISNUMBER(SEARCH({"namedrangeOfApps"},G2)))>0
Example of a cell could be:
"Microsoft.Office.v.21" In this case, if either Microsoft and or Office is found" Place the found entry in another Cell instead of just placing TRUE.
Source of original solution
With text in cell A1 try:
=IF(ISNUMBER(SEARCH("Office ",A1)),"Office","") & IF(ISNUMBER(SEARCH("Adobe ",A1)),"Adobe","") & IF(ISNUMBER(SEARCH("google ",A1)),"google","") & IF(ISNUMBER(SEARCH("Microsoft ",A1)),"Microsoft","")
While it does appear a little "brute force", it is easy to understand and will return more than one keyword if more than one keyword is present.
EDIT#1:
Here is a small User Defined Function. Its arguments are the cell being searched and a list of keywords (in the sample, it is a Named Range called "mikee" in column C):
Option Explicit
Public Function RetrieveKeys(rin As Range, KeyList As Range) As String
Dim s As String, r As Range
s = rin(1).Text
RetrieveKeys = ""
For Each r In KeyList
If InStr(1, s, r.Value) > 0 Then RetrieveKeys = RetrieveKeys & r.Value
Next r
End Function
It can handle a very large list of keywords and if a separator is required between multiple returns, it is easy to change.
try this
=IFERROR(INDEX({NamedRange1},MATCH(TRUE,ISNUMBER(SEARCH({NamedRange1},A10)),0)),"")
or
=IFERROR(INDEX({"microsoft", "google", "apple"},MATCH(TRUE,ISNUMBER(SEARCH({"microsoft", "google", "apple"},A10)),0)),"")
This works great
reference...
Searching for multiple text strings in a MS Excel cell and return the same string when found

Resources