SumIf with Strings? - string

This may be a stupid question, and if it is, I apologise. I have a table in excel:
Column a...........Column b
1 property1.......problem x
2 property2.......problemy
3 property3.......problemz
4 property1......problem a
I was wondering if I could use sumif (or any similar formula) to add the problems, referring to a certain property, in one cell. for ex:
I would have
Column a...........Column b
1 property1.......problem x problem a
The problem is I can't figure out where to start. I tried using sumif but I get an error. Probably because I'm trying to add strings. I tried to mix a vlookup with sumif but that didn't produce anything too. Im stuck here. Thanks for any help!

I am not 100 % sure, but I think you might need to use VBA for this. You could try to create the following custom function:
Create named ranges properties and problems in your sheet.
Click ALT+F11 to open VBA editor.
Press Insert --> Module
Write code
'
Function ConcatIF(Property As String, PropertyRange As Range, ProblemRange As Range) As String
Dim counter As Integer
Dim result As String
result = ""
Dim row As Range
counter = 1
For Each row In PropertyRange.Rows
If (Property = row.Cells(1,1).Value) Then
result = result + ProblemRange.Cells(counter,1).Value + " "
End If
counter = counter +1
Next row
ConcatIF = result
End Function
As I do not have excel on the machine I am writing this on, I could only test it on another machine, and therefore there could be spelling mistakes in this code.
Ensure that you write the code in the module you created, it cannot be written in a Sheet's code, must be module.
This function can then be called as a regular function, like sum, average and if. Create a unique list of all your properties on another sheet. Properties in column A, and then in column B you can call the cuntion. Assume row 1 is used for headings, write the following and copy down.
=ConcatIF(A2,properties,problems)
NOTE!!!! This code gets out of hand very quickly. It needs to do (number of properties) x (number of property/problem pairs) comparisons, so if this number is huge, it could slow down your sheet.
There could be faster methods, but this was from the top of my head.

Related

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

Excel no longer calculates my fields

I have written a simple VBA function to look up a value by key in a long table of key/value pairs. It then returns that value as a Double:
Public Function GetValue(sheet As String, key As String) As Double
Dim WS As Worksheet
Dim K As Range
GetValue = 0
Set WS = ThisWorkbook.Worksheets(sheet)
If WS Is Nothing Then Exit Function
Set K = FindKeyAnywhere(WS, key)
If K Is Nothing Then Exit Function
GetValue = WS.Cells(K.Row, 5).Value
End Function
I have about 60 of these formulas in a summary sheet:
=GetValue("Data", B$41)
Where "Data" is the name of the page with key/values, and B$41 is a key. Everything was working perfectly, then...
I fat-fingered the VBA, changing the = 0 to = o and calced. Now every cell on the summary still said #VALUE. When I realized what happened, I fixed the error and recalced. However, every cell on the summary still said #VALUE.
If I click in the cell and hit return, it updated fine.
I checked, autocalculate is turned on. I also clicked calc sheet several times. Nothing.
So I went to every single cell and hit return, so they were all updated. Now they don't say #VALUE, but they still don't update when I change data on the data page.
Is there anything special I'm missing? It seems like Excel is "stuck" thinking the calculation isn't valid.
UPDATE:
Using a named range does not work well, because it has to be typed into every formula. Consider...
KEY1 KEY2 ANOTHERKEY
Data1 =GetValue(A$1,B$1)
Data2
When the user CnPs or drag-fills that formula, it will get the key and sheet automatically. If we use a range name instead, they would have to type in the name in every single cell, and there's hundreds.
Is there a way to take a string and return the named range? Like =Range(A1)
As John Coleman says: Excel does not know it needs to recalculate when something on the Data sheet changes because the precedents of your UDF do not include the range od information on the Data sheet.
You need to:
Either Make the function Volatile - but this has bad recalculation
consequences.
Or pass the range on the Data sheet that contains the information
instead of passing a string. This is the best solution.
Based on your update I think you are looking for INDIRECT, which can convert a string to a range.
But there are major downsides to INDIRECT: its volatile, single-threaded and behaves badly when the string the user gives it does not exist.
IMHO this is not a good direction to go: I would recommend you consider a redesign of your data/algorithms.

how to write results of a formula directly into an excel range by VBA code

I have a series of functions for each of listobject columns. The file is heavy and crashing, so I want just to keep the results of each formula as static values. I can allocate formula to the range and ask excel to convert the range to value. But I am wondering if there is a way to ask VBA to write only the static values in the range instead of the formula itself.
Here is what I have so far:
Sub calculate2()
Dim i As Long, t As Long
t = Timer
With Sheet3.ListObjects(1)
For i = 3 To 9
.ListColumns(i).DataBodyRange.ClearContents
.Range.Cells(2, i).Formula = sheets3.range("formula").cells(i,1).formula
.ListColumns(i).DataBodyRange = .ListColumns(i).DataBodyRange.Value
Next i
End With
Debug.Print Timer - t
End Sub
As an answer to my own question,
What I was looking for is: " application.Evaluate " I am posting that so if anyone came here by search can find the idea and the sollution I eventually found. Here is an example:
Sheet3.ListObjects(1).ListColumns(3).DataBodyRange = [IFERROR(IF(COUNTIFS(ZZ84!$B:$B,[WO],ZZ84!$E:$E,"=*V99"‌​,ZZ84!$L:$L,"<>")=1,1,0),"")]
in this case there is no need to loop and for each range has to write needful line of code (Embed the function in VBA, what I excatly was looking for). The only different in above function with directly putting that in a excel cell is using [WO] instead of [#WO]. So evaluat caculate an array of data and directly write that in specified range. (here body range of list columns 3 ).
For me it helped to avoid crashes beacause of voilate calculation by my functions.
Another simple example would be:
range("b1:b10")=[if(row(1:10),if(a1:a10>3,"big","Small"))]
or
range("b1:b10") = evaluate("if(row(1:10),if(" & range("a1:a10").address&">3,""big"",""small""))")
Kind regards,
M

vba excel vlookup: lookup value in stored array, lookup table in excel, output value to array

I am using vlookup to populate an array in vba.
The array (InfArray) is an ~100 row by 3 column array. The first column of the array is already populated with integer values. These integer values correspond to a name. In one of my excel sheets I have a table that has each integer id listed with its corresponding name. So I want to use the vlookup function to check the id integer and populate the second column of the array with the actual name.
Here is the code statement I have to assign the second column (original bad code):
For y = 1 To UBound(InfArray,1)
Set InfArray(y,2) = Application.WorksheetFunction.VLookup(InfArray(y,1), NameSheet.Range("B2:C244"), 2, False).Value
Next y
It is giving me a Object variable or With block variable not set error.
When I cursor over the code text after running, I see that the
NameSheet.Range("B2:C244")
is where the object variable or with block variable not set error is located. This is really confusing. I put a
Debug.Print NameSheet.Name
In the code prior to the error and it is giving me the correct name of the excel sheet in question. So the code must be looking in the right worksheet, but somehow it is not getting the range...?
I'm lost, please help
EDIT: The error was a typo in the code
NameSheet.Range("B2:C244")
should have been
NamesSheet.Range("B2:C244")
Note the 's' at the end of NameS
It now works with the edits suggested
Working code line:
For y = 1 To UBound(InfArray,1)
InfArray(y,2) = Application.WorksheetFunction.VLookup(InfArray(y,1), NamesSheet.Range("B2:C244"), 2, False)
Next y
Apologies for the stoopid error.
Thanks for you help.
Get rid of the Set statement. It should only be used with object variables.
But also...
Piercing the boundary between VBA and Excel 100 times in a loop is not an efficient design. It would be much better to grab your table once, place it in a VBA array, and then just spin through this additional array to find the lookup values.
Remove the .Value from the VLOOKUP function. The Range.Value property is not part of VLOOKUP.
For y = 1 To UBound(InfArray,1)
InfArray(y,2) = Application.VLookup(InfArray(y,1), NameSheet.Range("B2:C244"), 2, False)
Next y
I've also reduced to down to Application.VLookup which is all that is necessary.

Excel conditional formatting for the entire row with more than one formula

After 3 hours of searching I still didn't find an answer, here is what I am trying to do:
I am trying to fill with green any row that has WBS in it and with Red any row that has ACT in it and Blue any row that has EPR in it. It works for the first formula then when I try to add the second one every thing get messed up.
what i have understood is that you need to search a keyword in a row and if its found in any cell of that row then color it.
May be we can do it with conditional formatting but i have another idea. We can create a simple search function in Excel VBA. Something like this:
=search_row(A1:F1,"EPR")
The function will return 1 if EPR is found in any cell of specified row. Now if you create two different columns at the end of data columns, name first with WPS and second with EPR and write this function in it. Like
G1 =search_row(A1:F1,"WPS")
H1 =search_row(A1:F1,"EPR")
Drag it to end. Now sort the columns. First for WPS from higher to lower. Then color all rows having 1 in a single select. Similarly do the same with EPR (H1) column.
To use this function you can download the macro file from the following URL:
http://asimishaq.com/myfiles/SearchHighlight.xlsm
Now to run it first of all enable macros, and then re-open your data file and then open this macro file. As long as this macro file is opened you can use this function. Following is the VBA code if you want to create the macro yourself:
Function search_row(sRow As Range, Keyword As String)
Dim i As Integer
Dim Found As Integer
For i = 1 To sRow.Columns.Count
If InStr(1, LCase(sRow.Cells(1, i)), LCase(Keyword)) > 0 Then
search_row = 1
End If
Next
End Function
I had a go at making a function similar to asim-ishaq to determine if your search term exists in the row for fun :) then tried to apply it to highlighting rows, turns out I dont know how to use conditional formatting very well! Figured it out in the end, hopefully I've explained it well enough.
With this you will have to have (one) extra column at the end of your data to contain the result.
It might be possible to not require the extra column by putting the function inside the conditional formatting, however I couldn't get it to work (didn't try very hard). This isn't a great loss as it's much simpler to edit the formula if its on the workbook, instead of having to go through each conditional rule to edit it, should you need to edit it in the future.
To get the formatting to work you will need to create a number of rules (one per keyword)
You want to create a rule of the type shown below, in the formula box you need something along the lines of: =INDIRECT("D" & ROW())=0 where D is the column containing the result of the function below and 0 is the index of the keyword you're highlighting.
In my example, the formula in the D Column is: =SearchRow(An:Cn,"ABS","KBS","JBS") (where n is the row the formula is on)
Set the formatting as desired then press OK, when you return to the rule manager you will need to update the Applies to value, which should be a range that covers all the data you want to highlight. In my example it was $A$1:$C$3
My function below takes 2+ Arguments, The first is the range to search. The second (and any subsequent ones) are search terms.
The function will return a number. -1 for no matches and 0+ for the found search term. The number depends on the position in the arguments.
A1 = "ABS"
B1 = "SBA"
A2 = "SBA"
B2 = "ABS"
A3 = ""
B3 = ""
C1 = "=SearchRow(A1:B1, "ABS", "SBA")"
C2 = "=SearchRow(A2:B2, "ABS", "SBA")"
C3 = "=SearchRow(A3:B3, "ABS", "SBA")"
C1 > 0
C2 > 1
C3 > -1
The function will always return the first result, searching left to right comparing each cell to the Keywords in order. Using my example, if a cell contained "SBA ABS" the result would be 0 (for ABS). I guess your cells will probably only contain one keyword though so this shouldn't be a problem?
Public Function SearchRow(ByVal Row As Range, ParamArray Keyword() As Variant) As Integer
Dim Column As Integer
Dim Value As String
Dim Index As Integer
Dim Result As Integer
For Column = 1 To Row.Columns.Count
Value = LCase(Row.Cells(1, Column))
Result = -1
For Index = LBound(Keyword) To UBound(Keyword)
If InStr(1, Value, LCase(Keyword(Index))) > 0 Then
Result = Index
Exit For
End If
Next Index
If Result > -1 Then
Exit For
End If
Next Column
SearchRow = Result
End Function

Resources