Can't evaluate Conditional Formatting of COUNTIF function - vba

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

Related

Excel VBA Compare cell value to list and overwrite value in separate sheet

In a workbook I have, users either manually enter an account code or select one from a list and the account codes are placed in column C (C7:C446) in a sheet called "JE". The account codes look like this ####### - ### - ## - ######. In column D (D7:D446) in sheet "JE", there is a formula that captures the last 6 digits of the account code. In a sheet called "required_refs", there is a list of 6 digit codes in column A. If the value in the D column in sheet "JE" equals any of the values in column A of "required_refs" sheet, I would like the value in the D column cell to overwrite the cell value in cell D1 in a separate sheet called "references" (I know that may have been confusing, sorry)
Example: if the value of D25 matches any of the values listed in column A of sheet "required_refs", upon double clicking a red colored F25 cell, put the value of D25 (of sheet "JE"), and put it in cell D1 on sheet "references".
I've taken a crack at it as best I know how. I've placed this code in sheet JE:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim project As Range: Set project = Range("D7:D446")
Dim param As Range: Set param = Worksheets("references").Range("D1").Value
For Each cell In project
If project.Value = Worksheets("required_refs").Range("A:A").Value Then
Call gotoRef_ 'macro that simply selects/navigates to the required_ref sheet
project.Value = param
End If
End Sub
Thanks so much in advance for any suggestions on how to complete this. I can elaborate on this further if needed.
This will do what you want:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If Intersect(Target, Range("F7:F446")) Is Nothing Then Exit Sub
Dim varReference As Variant
varReference = Columns("D").Cells(Target.Row).Value2
If Not IsError(Application.Match(varReference, Worksheets("required_refs").Columns("A"), 0)) Then
Worksheets("references").Range("D1").Value = varReference
End If
End Sub
Important Points:
Whenever working with event handlers, always limit the scope of the target range in the first line. Otherwise, it might not work correctly or it could slow done your spreadsheet.
Make sure your JE sheet column D values and required_refs sheet column A values are all either text or numbers. Otherwise the values won't be compared correctly.
Note the usage of Application.Match() instead of WorksheetFunction.Match() to access the worksheet function. This, coupled with the use of a Variant type variable, allows us to trap the error that occurs if the match fails.
You can always do this on the sheet. Consider the MATCH function. See here for how to use MATCH.
Or another great tool if you're searching for something in a table associated with a value in another column (not your case I don't think)--VLOOKUP formula. Place this formula in the D cell of the sheet you want to place the numbers in. VLOOKUP is in the following format:
=vlookup(lookup value,table_array,column index number, [range lookup])
The lookup value is the 6 digit code you're looking for (on the JE sheet)
The table_array is simply selecting the values you want to search for (required_refs sheet)
The column index number would be one, since the table only has 1 column. It's basically the column number of the value you're looking for.
And range lookup is for if you think there might be more than one place where it matches.
For your case I think it would look like this:
=vlookup('JE'!D1,'required_refs'!A1:A,1,FALSE)
Then just lock the values you want to keep and click and drag down.
Explanation for VLOOKUP here

Variable Named Ranges in Excel

I have a table in Excel formatted as follows:
Date Asset Return
1/3/2005 0.003582399
1/4/2005 -0.01908258
1/5/2005 0.002080625
1/6/2005 0.005699497
1/7/2005 -0.008040505
1/10/2005 -0.00339116
1/11/2005 -0.009715187
1/12/2005 0.002371855
1/13/2005 -0.00580783
1/14/2005 0.001058481
1/18/2005 0.015483842
1/19/2005 -0.014690715
1/20/2005 -0.015714799
1/21/2005 -0.010796326
I need a named range to reference each column. The workbook is a template, so the named range won't always cover the same number of rows depending on the data. I want to set it so that the named range "Date" and the named range "Asset Return" are automatically sized to cover the entire column from the first value until the last, without going past the last value in the column.
It will always start at cell B8, but might end at a different row depending on the size of the data.
How can I set a dynamic named range to accomplish this?
This named range formula will do it:
=Sheet1!$B$8:INDEX(Sheet1!$B:$B,COUNTA(Sheet1!$B:$B)+8)
Remember to add the sheet name as the named range will operate on the active sheet otherwise.
The formula starts takes B8 as it's starting point: Sheet1!$B$8
It then counts how many cells are not blank in column B: COUNTA(Sheet1!$B:$B)
It adds 8 to the count (assuming your first rows are blank).
It then uses INDEX and the COUNTA to reference the last cell.
https://support.office.com/en-gb/article/INDEX-function-a5dcf0dd-996d-40a4-a822-b56b061328bd
https://support.office.com/en-gb/article/COUNTA-function-7dc98875-d5c1-46f1-9a82-53f3219e2509
Try this VBA code
Sub test()
application.DisplayAlerts = false
Range("B8").currentregion.createnames _
top:true, right:=false, left:=false, bottom:=false
application.DisplayAlerts = true
end sub

Return values from other workbook

Have a question about formula which will resolve my issue.
In my main workbook I need to compare data from two sources.
One of the columns must retrieve data(amounts) from other workbook.
I want formula which will search for all amounts in column G and will skip all blank cells. Tried to use VLOOKUP, INDEX and SMALL functions but no effect.
Each day amounts are different and I need to match them in main file and find exeptions.
Any ideas?
How about an array formula such as the following?
=INDEX($G$2:$G$20,SMALL(IF(($G$2:$G$20)=0,"",ROW($G$2:$G$20)),ROW()-1)-ROW($G$2:$G$20)+1)
The formula would have to be placed into cell I2 as an array formula (which must be entered pressing Strg + Shift + Enter). Then you can drag down the formula to get all the other values.
It doesn't have to be in column I but it has to be in row 2 because this formula get's the n-th Number from the list which is not = 0. The n-th place is (in this formula) row()-1. So for row 2 it will be 2-1=1 and thus the 1st number. By dragging down the formula you get the 2nd, 3rd, etc. number. If you start with the formula in cell I5 instead then it would have to be adjusted to be as follows:
=INDEX($G$2:$G$20,SMALL(IF(($G$2:$G$20)=0,"",ROW($G$2:$G$20)),ROW()-4)-ROW($G$2:$G$20)+1)
You could loop through the column and store each value >0 in an array and then compare or you loop through the column and compare directly...
something like:
Dim i as Integer = 0
Foreach value in Maintable
Do
If otherworkbook.cells(i,7) = value Then '7 for G
do your stuff
End If
i = i + 1
While i < otherworkbook.rows.count
Next
I think that could be the right approach

Excel: Check if cell string value exists in column, and get all cell references to that string

I suspect this may be a job for VBA, which is beyond my abilities. But here's the scenario:
Column A in Sheet 1 (CAS1) contains x rows of text values
Column A in Sheet 2 (CAS2) contains x rows of text values
Part A - For each row value in CAS1, I need to know if the string is contained in any of the cells in CAS2. Not exact match, the string can be only part of the searched cells.
Part B - I need to know the cell value of each cell in CAS2 that contains the CAS1 value (if they do exist, they can be listed in the cells adjacent to the cell being searched in CAS1).
I've tried the following to attempt Part A, all to no avail:
vlookup(A1,sheet2!A:A,1,false)
NOT(ISNA(MATCH(A1,sheet2!A:A,0)))
ISNUMBER(MATCH(A1,sheet2!A:A,0))
COUNTIF(sheet2!A:A,A1)>0
IF(ISERROR(MATCH(A1,sheet2!A:A, 0)), "No Match", "Match")
I know some of the cell values in CAS2 contain the cell values in CAS1, so I don't know why they return false or No Match. I suspect it may be down to the nature of the text content. So here's some sample data:
CAS1
LQ056
RV007H
RV008
RV009H
TSN304
TSN305
CAS2
RV009-satin-nickel-CO.jpg
STR314.jpg
STR315.jpg
HCY001.jpg
RV008-oval-rad-CO.jpg
HCY001-BRAC006.jpg
Any help would be appreciated.
This problem can be faced through VBA (at least, I imagine the VBA solution much more easily than the possible Excel one). You need a macro that, for each row in CAS1, search the content in each row of CAS2 and returns you the address.
For Each cell In Sheets("CAS1").Range("A1:A" & Sheets("CAS1").Range("A1").End(xlDown).Row) '<-- check each cell of the range A1:A? of sheet CAS1 (adapt "A" and "1" if they're different)
recFound = 0 '<-- count how many findings there are
For Each cell2 In Sheets("CAS2").Range("A1:A" & Sheets("CAS2").Range("A1").End(xlDown).Row) '<-- check in each cell of the range A1:A? of sheet CAS2 (adapt "A" and "1" if they're different)
If InStr(cell2.Value, cell.Value) <> 0 Then '<-- if the value in cell is contained in the value in cell2..
recFound = recFound + 1 '<-- account the new finding
cell.Offset(0, recFound) = Split(cell2.Address, "$")(1) & Split(cell2.Address, "$")(2) '<--write the address on the right of the currently searched cell
End If
Next cell2
Next cell
All the above should be enclosed in a macro, e.g. Sub makeMySearch(), that should be run to get the results. As commented in my code, I'm assuming that data are in A1:A? of both sheets; but they of course might be, for example, in B5:B? of the sheet 1 and in C7:C? of the sheet 2. You need clearly to adapt the code to your current data.
There's no need for VBA. Some simple array-formulas can do the job.
To see if the entry in CAS1 is present in CAS2:
=OR(ISNUMBER(SEARCH(A2,CAS2_)))
will return TRUE or FALSE. BUT this formula has to be entered by holding down CTRL-SHIFT while hitting ENTER If you do this correctly, Excel will place braces {...} around the formula that you can see in the formula bar.
The SEARCH function returns an array of results, which will be either the #VALUE! error, or a number.
In order to return the address, the following array-formula can be entered adjacent to a cell in CAS1:
=IFERROR(ADDRESS(LARGE(ISNUMBER(SEARCH($A2,CAS2_))*ROW(CAS2_),COLUMNS($A:A)),1),"")
Fill right for the maximum number of addresses possible, then select the group and fill down.
In this case, the array being returned is a string of either 0's, or 1 * the row number (i.e. the row number). I assumend the data in CAS2 was in column A, but you can change the column number if needed (or even compute it if necessary, by replacing the 1 in the ADDRESS function with COLUMN(CAS2_))
CAS1_ and CAS2_ are either named ranges, or absolute range references to the two text groups.

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

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).