How to SUMIF (or ??) using criteria from another function value return? - vba

I am trying to do a very simple sum of a column that excludes the colored ones. The column I wish to sum is all my accounts and the green ones represent the paid accounts. I want a sum that represents the "left to pay" value to keep track of my progress without redoing my formula every time. The color is not conditional, nor can it be.
I have 2 functions created already:
Function GetColor(MyCell As Range)
GetColor = MyCell.Interior.ColorIndex
End Function
and
Function PAID(MyCell As Range) As Boolean
If MyCell.Interior.ColorIndex = 50 Then
PAID = True
Else
PAID = False
End If
End Function
So I have already created one column next to my numbers that have the formula (with changing cell number):
=PAID(C13)
and this spits out TRUE or FALSE values that I can then based my SUMIF formula off of, currently I have this (E column containing values from the PAID function, C contains my account values):
=SUMIF(E2:E18,"FALSE",C2:C18)
I would like to see if it's possible to bypass making this extra column and run the function directly in the SUMIF (or maybe another function?) so that all I have to do is color my cell and refresh only one formula.

Using colours as part of the program decision process is not ideal, and is overly complex for a simple task.
But assuming you want this (or have no control over this), and the cells you want to sum are NOT coloured with Interior.ColorIndex = 50 - and assuming your values are in range C2:C18 (or wherever), a VBA function to do this is below.
Use the function as =PAID(C2:C18,50)
Function PAID(MyCells As Range, colour_avoid As Integer) As Double
Dim cc As Range
Dim accumulate As Double
accumulate = 0 'not needed but good practice
For Each cc In MyCells
If (cc.Interior.ColorIndex <> colour_avoid) Then
accumulate = accumulate + cc.Value
End If
Next cc
PAID = accumulate
End Function
To repeat, this function will sum all the cells NOT coloured with a colour.index that you give to it (say, 50).

Related

(VBA) Custom function refreshing itself with wrong input?

My problem is hard to explain, therefore I added a picture and also shared the sample excel file via my google drive.
What the function should do: Have different item total prices in row "W" and the percentage of transportation costs within the total prices in row "Q" (several other percentage-rows exist for different cost items, this is just to simplify).
Now I SUM the individual item totals.
Then, I apply below function to all percentages in row "Q", which should then give me the total amount of costs, which I then can devide again by row "W" to get the cost percentage of the total.
In my example file, all sub-percentages are equal, but they could as well be different.
The problem that I encounter occurs when I have two sheets with the function below. For some reasons, whenever the function updates on one sheet (and shows the correct value), the function on the other sheet becomes a mess. When I then manually update ("press enter") on the messed-up function, it shows the correct value, but when I go back to the previous sheet, the function is messed up there... I am going crazy : (
And, if I have a third sheet that references "Q" on each sheet, I can never get it to show the correct value for both sheets at the same time, one is always incorrect.
Option Explicit
Dim rCell As Range
Function SUMSubCost(rRange As Range) As Double
Application.Volatile
Dim Total
For Each rCell In rRange
If (Not IsEmpty(rCell)) And (Not IsError(rCell)) Then
Total = Total + (rCell.Value * Range("W" & rCell.Row).Value)
Else
End If
Next rCell
SUMSubCost = Total
End Function
Excel Document
Picture
Without a qualifying worksheet object, your Range("W" & rCell.Row) will always refer to the ActiveSheet, which is not always the one calling your function.
Here's one way to fix it:
Option Explicit
Function SUMSubCost(rRange As Range) As Double
Application.Volatile
Dim Total, rCell As Range
For Each rCell In rRange
If (Not IsEmpty(rCell)) And (Not IsError(rCell)) Then
Total = Total + (rCell.Value * rCell.Worksheet.Range("W" & rCell.Row).Value)
End If
Next rCell
SUMSubCost = Total
End Function

Excel If Cell Is Highlighted on VLOOKUP

I have two sheets in excel, one is an order form the other is a production sheet based off the order form.
I am using VLOOKUP to query the order form for the quantity of a given item ordered.
However, sometimes this quantity is highlighted on the order form, indicating that the item in question actually gets produced 2 extra amounts (for free samples).
So for example, in the production form I have:
ITEM|QUANTITY TO PRODUCE
In the order form I have:
ITEM|QUANTITY TO ORDER
I use VLOOKUP to get the match, and this works, but if a cell in QUANTITY TO ORDER is highlighted yellow, then I need the VLOOKUP value to be added by two.
How can I do this? Is there a way to do this automatically, without a macro? My client doesn't want to be manually activating things, they just expect the sheet to work.
Thank you.
VLOOKUP can't do that. What you need to do, is treat a cell's background color as data... and a cell's background color isn't data.
But... this link explains how to do that and what the implications are.
Create a workbook-scoped name (Ctrl+F3) called BackColor referring to =GET.CELL(63,OFFSET(INDIRECT("RC",FALSE),0,-1)), and then add a column immediately to the right of the column where the user highlights cells, and make that column have a formula such as =BackColor<>0 so that it contains TRUE for any highlighted cell in the column immediately to its left.
Hard-coding the extra 2 units into your formula isn't going to be maintenance-friendly, so enter that 2 in a cell somewhere and define a name called ExtraUnits for it.
Then modify your formula to
=[the original VLOOKUP]+IF([lookup the BackColor Boolean], ExtraUnits, 0)
This will add ExtraUnits to the looked up units, for all highlighted cells.
The only drawback is that, as I said above, a cell's background color isn't data as far as Excel is concerned, so your user must trigger a recalculation - just changing cells' background color will not do that, but pressing F9 will.
The below code was found at http://www.mrexcel.com/forum/excel-questions/215415-formula-check-if-cell-highlighted.html
Function CellColorIndex(InRange As Range, Optional _
OfText As Boolean = False) As Integer
'
' This function returns the ColorIndex value of a the Interior
' (background) of a cell, or, if OfText is true, of the Font in the cell.
'
Application.Volatile True
If OfText = True Then
CellColorIndex = InRange(1,1).Font.ColorIndex
Else
CellColorIndex = InRange(1,1).Interior.ColorIndex
End If
End Function
To use the function:
=IF(CELLCORINDEX(A1,FALSE)>0,1,0)
This lets you check the color of the cell , or the text. But you will need to use the Index-match code found here http://www.mrexcel.com/forum/excel-questions/447723-vlookup-returns-cell-address.html in order to match it up.
Also, like the above answer states, highlighting a cell doesn't count as a data change, so even though you can get this info without a macro, if someone updates the cell's highlight status, it will not update the cells using this formula unless automatically.
Sounds like you may need to rethink the Highlighting being the trigger of the +2 samples. I'm with the above answer that recommends adding a column maybe True/False or Yes/No that is checked to see if they get samples.
What I did is this:
I created a user defined function:
Function getRGB3(rcell As Range, Optional opt As Integer) As Long
Dim C As Long
Dim R As Long
Dim G As Long
Dim B As Long
C = rcell.Interior.Color
R = C Mod 256
G = C \ 256 Mod 256
B = C \ 65536 Mod 256
If opt = 1 Then
getRGB3 = R
ElseIf opt = 2 Then
getRGB3 = G
ElseIf opt = 3 Then
If B <> 0 Then
B = -2
End If
getRGB3 = B + 2
Else
getRGB3 = C
End If
End Function
This made it so all the highlighted cells (in yellow) got a value of 2 when referred to, so on the order form it goes like ITEM|QUANTITY TO ORDER|CUSTOM FUNCTION VALUE| and the third column (custom function) is 2 for each corresponding yellow cell next to it, if not, it is just zero.
Then I do a second VLOOKUP to add the CUSTOM FUNCTION VALUE to the original, and then I have added two. :)

#VALUE error with Excel VBA Function

In my Excel spreadsheet I have two columns.
A contains strings with the values 'Yes', 'No' or 'Maybe'.
B contains strings with a year in.
I need a function to determine the number of occurrences of a year in column B, where the equivalent value in column A is 'Yes'.
I currently have the following code:
Function CountIfYearAndValue(Rng As Range, YNM As String, Year As String) As Integer
Dim count As Integer
count = 0
For Each c In Rng.Cells
If (StrComp(Abs(c.Value), Year, vbTextCompare) = 0) And (StrComp(Cells(c.Row, A), YMN, vbTextCompare) = 0) Then count = count + 1
Next
CountIfYearAndValue = count
End Function
The idea of this code is that we iterate through every cell in the range given (a range on column B) and check if the year is equal to the Year parameter. And if the equivalent cell on column A is equal to the YNM parameter we increment the count variable.
For some reason this code does not work when I use the following parameter:
=CountIfYearAndValue('Years'!B1:B7,"Yes","Year 7")
It just does the #VALUE error and refuses to display any outcome.
Any help would be much appreciated.
Edit: All of the values in both cells are on of an unformatted datatype ('General') and no cells are blank.
It sounds like you are reinventing the wheel... There already is a built in function (advantage: being much faster than a UDF) that does exactly what you are after. It is called COUNTIFS()
All YESes for Year 7 in rows 1 to 10.
=COUNTIFS(B1:B10, "Year 7",A1:A10, "Yes")
I just had a quick look at your code and I think there are possibly a few reasons why your original code is not working as expected.
YNM is a valid column name therefore it should not be used as a variable name. You should avoid naming your variables like that - give it a more meaningful name
YNM != YMN as you had it in your code (see function definition and then the misspelled version in the StrComp() function)
Year is a valid VBA built in function, therefore once again you should avoid using it as a variable name as you're exposing yourself to a naming collision.
Add Option Explicit at the top of your module. This requires you to Dimension all you variables. It's always recommended for many many reasons.
rng variable is of Range type therefore you do not need to explicitly add the .Cells property to it. Even though it may help in some cases - at a bit more advanced level you may face some runtime type compatibility issues. ( runtime may convert your rng Range variable to a 2D array etc )
Added an explicit conversion in the second StrComp() function around the c.Offset(0, -1) as you don't want the runtime to (rare but still possible) convert your Yes to a Boolean data type. Explicit conversion to a String just gives you that extra protection ;p (lol)
therefore, something like this returns the correct value
Function CountIfYearAndValue(rng As Range, choice As String, myYear As String) As Long
Dim count As Long
count = 0
Dim c As Range
For Each c In rng
If (StrComp(c, myYear, vbTextCompare) = 0) And (StrComp(CStr(c.Offset(0, -1)), choice, vbTextCompare) = 0) Then
count = count + 1
End If
Next c
CountIfYearAndValue = count
End Function
Right, I hope this helps you understand bits and pieces :) any questions please leave a comment

Can't evaluate Conditional Formatting of COUNTIF function

I'm having problems checking if my conditional formatting equates to true in VBA. Formatting works correctly on the spreadsheet and changes the cell colours but VBA is showing no conditioning is applied when the COUNTIF function is used.
On each cell within a range I have set up three conditions:
1: =WEEKDAY(DATE($B$4,$A$5,$C$4),2)>5 - Changes colour if the day is a weekend (light blue)
2: =COUNTIF($AL:$AL,DATE($B$4,$A$5,$C$4))>0 - Checks a range (AL column) to see if the date appears in it (dark blue)
3: =COUNTIF($AM:$AM,DATE($B$4,$A$5,$C$4))>0 - Same as above but checks a different column (yellow)
Its a holiday spreadsheet. Column AL holds any public holidays that are set and column AM holds holidays that the company sets. The calendar then highlights the grid with weekends and holidays
B4 - Year
A5 - Month
C4 - Date
A5 & C4 addresses change depending what cell is selected however I have had to use absolute addresses as evaluate doesn't work with relative addresses.
In my VBA code I need to check if a condition has been applied and put a value of "P" for public hols or "Z" for company hols. When running the VBA however it does not recognise that these conditions have been met.
Condition 1 is picked up on as TRUE but it does not see when the other 2 conditions have been met even though the colours have changed on the sheet?
I tried taking out the DATE within the COUNTIF and hardcoding a string but still didn't pick it up in VBA so it's not that.
To return the active condition in VBA I am using:
For Ndx = 1 To Rng.FormatConditions.Count
Set FC = Rng.FormatConditions(Ndx)
If Application.Evaluate(FC.Formula1) Then
ActiveCondition = Ndx
Exit Function
End If
Next Ndx

Macro to run through 3 conditions and provide value

This is my first time using VBA for Excel (I usually code Java and C++), and I was hoping to get some tips to start out.
I want to write a macro for a large data set that will proceed through the following list of conditions to provide a dollar result:
Collect unit size from column A (Possible values 0-8)
Determine whether single or family unit from Column B (Single- 1, Family- 0)
Collect utility code from Column C (code for type of product being assessed)
From this information, a new value will be placed in the row which determines utility costs by taking into account unit size, type of unit, and the product in question. I have thought about using nested Select Case or nested conditionals in a loop, but overall I am pretty lost.
It seems like a worksheet formula might do the trick, but it's hard to tell without knowing what the calculation is. Below is a user-defined function (UDF) that you would put in a standard module. You would call it from a cell like:
=computecosts(A2,B2,C2)
Obviously the code would change depending on how your data is laid out and what your calculation is.
Public Function ComputeCosts(rSize As Range, rFamily As Range, rCode As Range) As Double
Dim lSizeFactor As Long
Dim lFamilyFactor As Long
Dim dCodeFactor As Double
Dim rFound As Range
Const lFAMILY As Long = 0
'Size factor is a function of 0-8, namely adding 1
lSizeFactor = rSize.Value + 1
'Family factor is computed in code
If rFamily.Value = lFAMILY Then
lFamilyFactor = 3
Else
lFamilyFactor = 2
End If
'Code factor is looked up in a different sheet
Set rFound = Worksheets("Sheet2").Columns(1).Cells.Find(rCode.Value, , xlValues, xlWhole)
If Not rFound Is Nothing Then
dCodeFactor = rFound.Offset(0, 1).Value
End If
'do the math
ComputeCosts = lSizeFactor * lFamilyFactor * dCodeFactor
End Function
Thanks for the responses, they were helpful in understanding VBA for Excel. I just ended up putting possible values in a table and then using Match functions within an Index function to pick out the right value.