VBA Range.Find function on rounded negative numbers - excel

I'm having an issue with a VBA macro I wrote, with the part that is intended to find a lowest value in range. The line looks like this:
Min = Application.WorksheetFunction.Min(a0eqB)
Set MinCell = a0eqB.Find(Min, LookIn:=xlValues)
And it returns Object variable or With block variable not set error. Now, I know why this happens - sometimes Find finds Nothing, and I learned how to handle this type of situations. Although, it also finds Nothing when the value that is dispayed in a cell differs from the value in Min variable.
For instance, when Min = -11.2641373534338, the value in a cell is -11.264137, and then error occurs. But if I change the number of decimal places displayed for that cell via Excel UI buttons until it is -11.2641373534338, everything works fine. Value in a cell is actually a formula calculation result if that helps.
I see two ways of dealing with this issue:
Finding out how many decimal places are being displayed and then rounding actual value so they match. But this way matching actually might go wrong, since numbers like 11.321 and 11.322 if rounded to 2 decimal places will be the same. Also, it's not possible due to the fact that I need to find the cell's adress in order to do that, and that's done in line 2 of the code above that's causing an issue.
Somehow telling Find function to use actual and not displayed numbers, but I've got no idea on how to do that. I googled for several days but still no success.
I will really appreciate you help.

There are at least two possible problems:
don't use Min as a variable name
Dim the variable you do use
For example:
Sub GetLowest()
Dim wf As WorksheetFunction
Set wf = Application.WorksheetFunction
Dim rng As Range, Lowest As Double, WhereIs As Range
Set rng = Range("A1:F9")
Lowest = wf.Min(rng)
Set WhereIs = rng.Find(What:=Lowest, After:=rng(1))
MsgBox WhereIs.Address
End Sub
when run on:
has no trouble finding B2 regardless of formatting.

Having looked at the issues with negative numbers and using it with the find function; a possible solution would be to format your search range and number to find with the same number format. (Based on code supplied by #Gary's Student)
Code is below for this.
If you don't want to alter the number formats in your spreadsheet, then a further hack would be to make a copy of the worksheet to format and find the address then delete the copy and use the address in the original sheet, but that would involve a bit more coding...
Sub GetLowest()
Dim sFormat As String: sFormat = "0.000000000"
Dim wf As WorksheetFunction: Set wf = Application.WorksheetFunction
Dim rng As Range: Set rng = Range("MinRange")
rng.NumberFormat = sFormat
Dim Lowest As Double: Lowest = Format(wf.Min(rng), sFormat)
Dim WhereIs As Range: Set WhereIs = rng.Find(What:=Lowest)
MsgBox WhereIs.Address
End Sub

Related

Named range to hide/show columns

I have a string that can take a couple of values (e.g. Madison, Chicago,...) and a couple of ranges named (Madison_Range, Chicago_Range,...)
Depending on the input of the user (more specifically, he drops an 'x' in a certain cell), the string takes on a certain value and I want the corresponding (hidden) range to be shown.
However,
Dim X as string
Dim Combination as string
x = Range("ACity:ZCity").Find("x").Name.Name
Combination= x & "_Range"
Range("Combination").EntireRow.Hidden
Does not do the trick, probably because vba looks for the named range "combination". Any ideas how to procede? I know that there is possibly a more elegant case, but this is a quick fix solution as part of a wide problem.
Dim X As String
Dim target As Range
X = Range(Range("Acity"),Range("zcity")).Find("x").Name.Name
'this is potentially dodgy - you assume that the find will find an x - if it doesn't it will error. Also you need to refer to each name with a separate Range function to turn it into a cell reference and then an external range function to turn those two cell references into a full range.
Set target = Range(X & "_Range") 'point to the range
'to hide
'target.EntireColumn.Hidden = True
'to unhide
target.EntireColumn.Hidden = False

Copy range based on a date

I'm new to VBA, my experience is basically record macros and adapt them a little bit, and i´ve been playing with a macro to copy a filtered range in sheet 1 based on a date value located in sheet 2 range "C42", the copy part is working
I have tried a couple of solutions i found on the internet but they don't work for me and I can't find the mistake (probably very simple but my lack of knowledge prevents me from finding it)
Sub CopyPaste
If Worksheets("Costos Médicos").Range("C42") = Worksheets("CC1").Range("B101") Then 'both values are visually in date format "dd/mm/yyyy" but if changed to general give a number
Call Cost1 'This is a macro currently working
ElseIf Worksheets("Costos Médicos").Range("C42") = Worksheets("CC1").Range("B102") Then
Call Cost2 'This one also works fine
end if
End Sub
'I also tried this, I've tried declaring cm as long, string, date, but all returns error 9 (again lack of knowledge)
Dim src As Worksheet
Dim tgt As Worksheet
Dim cm0 As Range
Dim cm1 As Range
Dim cm2 As Range
Set src = ThisWorkbook.Sheets("CC1")
Set tgt = ThisWorkbook.Sheets("Costos Médicos")
Set cm0 = src.Range("C42") 'This is the given date
Set cm1 = tgt.Range("B101") 'This is a date
Set cm2 = tgt.Range("B102") 'This is another date
If cm0 = cm1 Then
Call Cost1 'this Works fine by itself
ElseIf cm0 = cm2 Then
Call Cost2 'this also Works
End If
I think the problem is simple but can't find the answer, I have tried multiple solutions online but they usually are for far more complicated things that I don't understand. Any help would be greatly appreciated.
I am quite sure that one of the Worksheet Names is typed incorrectly, as Error 9 means that you called an element by name or position which is not present, so "out of range".
Change the names of the sheets to x and y for a test.
Concerning the dates: You do not need to worry about the formatting. Every whole day is represented by a whole number. Hours, Minutes etc. are fractions thereof. Dates are stored as Floating point numbers (both in cells an in VBA) and can be compared to other dates or integers with no problems.

Offsetting a range that is found manually

I have a situation where I am using these equations
=CELL("address",INDEX(J61:W61,MATCH(LARGE((J61:W61),1),J61:W61,0)))
To find the cell address of the largest value cell in that range.
For example, it gives me this as a result. $T$61 (which contains the highest value).
I now want to use that information and offset it upwards 51 rows to extract the title for this column. How can I use this information and a formula, or VBA to find the content of $T$10 in this case?
Obtaining the cell address in this case is not necessary. What's more, CELL is a volatile function, and so should be avoided if possible.
Simply:
=INDEX(J10:W10,MATCH(MAX(J61:W61),J61:W61,0))
Regards
I ended up finding a way to use vba to do what I need
Sub Top_3_Problems()
First_Address = Range("D62")
Second_Address = Range("D63")
Third_Address = Range("D64")
First_problem = Range(First_Address).Offset(-51)
Second_problem = Range(Second_Address).Offset(-51)
Third_problem = Range(Third_Address).Offset(-51)
Range("B40") = First_problem
Range("B41") = Second_problem
Range("B42") = Third_problem
End Sub
Quick example of how to do this in VBA
This is just a simple example. If implemented, objects need to be properly qualifed with a worksheet and the Find method needs to have options added
Option Explicit
Sub MaxHeader()
Dim Found As Range, SearchRange As Range
Set SearchRange = Range("J61:W61")
Set Found = SearchRange.Find(WorksheetFunction.Max(SearchRange))
If Not Found Is Nothing Then MsgBox Cells(10, Found.Column)
End Sub

Using a variable for a range

I am writing a macro and am having issues with using a range variable. I think I am setting the range properly, but I cannot do anything with the range. Pseudocode below:
Dim rng As Range
Set rng = Report(1) 'A function which will be defined below
trackWkbk.Sheets(strFY).rng = 10 <--'THIS IS WHERE I am getting the error.
'trackWbkb is a workbook that is defined properly; I use it elsewhere with no errors.
'strFY is defined and working properly, I use it to call sheets in trackWbkb elsewhere with no errors.
The sub function code is:
Function Report(a) As Range
Select Case intMonth
Case intMonth = 7
Select Case a
Case a = 1
Set Report = Range("B2")
End Select
End Select
End Function
I know my select case statements are gonna get pretty convoluted (this is just a testing sample), but I don't think the issue is there.
Let me know if I should include more code. My code compiles. I think this is something simple that I am missing, but I have been looking online for the past half hour and can't seem to find anything that will resolve this. Does anyone know how to resolve this? Thanks
Your function already returns a Range object. It's not clear to me whether you're trying to obtain a range on another worksheet that is at the same address as a range on the active worksheet. However, you could directly obtain the desired range if you passed the worksheet reference to your function:
Function Report(ByVal poParentWorksheet As Excel.Worksheet, ByVal a As Integer) As Range
Select Case intMonth
Case intMonth = 7
Select Case a
Case a = 1
Set Report = poParentWorksheet.Range("B2")
End Select
End Select
End Function
Then you could use:
Set rng = Report(trackWkbk.Sheets(strFY), 1)
rng.Value = 10
When you set a range variable you are creating a pointer in memory to a specific range in a specific sheet. It's not storing a cell address, so you can't write
trackWkbk.Sheets(strFY).rng
Either adopt Excelosaurus's solution, or change your function to return a cell address as a string and then use
trackWkbk.Sheets(strFY).range(rng)

Use Named Range in UDF

I'm trying to create a UDF that will use a named range. My named range ("best_Grade") is a single cell, with a value. (The named range is scoped to the Workbook).
In a workbook module, when I try to create the variable using a named range, I get
Run-time error '1004': Method of 'Range' of object '_Global' failed
Neither line works:
Dim namedRng As Range
Dim locDataWS As Worksheet
Set locDataWS = Sheets("Approval matrix 16")
Set namedRng = Range("best_Grade") ' errors
Set namedRng = locDataWS.Range("best_Grade") ' When I take above line out, this line errors too
and I've tried:
Dim wb As Workbook
Set wb = ActiveWorkbook
Set namedRng = wb.Names("best_Grade").RefersToRange
How come it's erroring out? This page says it should be working, no? Do I have to put this UDF on the actual sheet object, and not in a workbook module?
Edit: Note: the named range is not set to a cell, but a SumIf formula (best_Grade = SumIf(A2:A10,"x",...)` which may be causing the error?
Edit2: Yeah, that's why I think. I created a named range for a random cell, and was able to use Range("a_grade").Value and it returned the expected value. Since my best_Grade range is a formula, I think that's why it's erroring out. However, I don't know why, as I'd think a named range is a named range, no matter what it's made up of...
Edit n+1: Note there are two "answers" to this. If I wanted to continue using a named range as a Range variable, see my answer below. However, what I really wanted to do was what #MacroMarc posted, so I chose that as the "Answer".
You need to use the Names collection instead:
Sub t5()
' named range "Test" is `=Sum($A$1:$A$4)`
Dim rng As Double
rng = Evaluate(Names("Test").Value)
Debug.Print rng
End Sub
There are various properties that Name objects have to return string representations.
Sub t5()
' named range "Test" is `=Sum($A$1:$A$4)`
Set wb = ActiveWorkbook
Dim rng As String
rng = wb.Names("Test").RefersTo
Debug.Print rng
rng = Application.Evaluate(wb.Names("Test").RefersTo)
Debug.Print rng
End Sub
After some testing I found the above worked...and kind of interesting. I got the lead from Macro Man's comment as well at Chip Pearson post.
The key is the defined names returns a string ="your result" so you can either evaluate it to get the answer, or you can do some string manipulation to pull off the quotes and equal sign. You really were close with your RefersToRange choice.
See Vegard's comment under your own posted answer.
The reason it wasn't working is because my named range best_Grades was not a cell reference, but a formula instead. Thus, when using Range("best_Grades").Value, it was erroring out. (best_Grades = SumIf(A2:A10,"x", B2:B10, ...)
Not sure why, since I'd think a named range is a named range, regardless of what makes that up...but I suppose not.
For now, my solution is just to create another named range, based on an actual cell value, and then use that. (theBest_Grades = A2). Then, I can call simply Range("theBest_Grades").Value without any issues.
I'll leave this open for a few days, in case someone has an idea of how I can keep my formula named range, and use that in VBA.
Edit: This was basically how I originally had the worksheet/named range:
with the named range being given as:
But, as I said, you can't use that type of named range in VBA (at least not that I have found).
So, to solve it, I just used that SumIf in the cell, and gave that cell the named range:
And now I can use Range("findWindow_Example").Value without issue.
Edit n+1:
I tried doing a simple test with a Double, same thing though, it errors out:
Sub t5()
' named range "Test" is `=Sum($A$1:$A$4)`
Dim rng As Double
rng = Range("Test") 'Run time error 1004
Debug.Print rng
End Sub
One thing I haven't seen mentioned here is that a ground rule for UDF's is broken here IMHO:
ALL information a UDF needs should be passed to the UDF through its arguments.
If you adhere to that rule, using any range name becomes simple, since the value of the range name will automagically be transferred to the argument.
The correct way to solve the problem has been found by more than one answerer, but as I said in the comments (and subsequently, thought might be of interest to others), the reason for the error wasn't specified yet.
The named range you defined does not return a range object. This means that this code:
Dim namedRng As Range
Set namedRng = Range("best_Grade")
couldn't possibly work (primarily because the named range returns a numerical value. If it returned a string address representation, it might have worked with some syntax improvements).
To illustrate this from the compiler's point of view, look at the print-outs in the immediate window here (the first line in particular):
If we assume the initial code to be pseudo-code, what was being asked of the compiler was to construct a range out of the formula (not its' result either!).
So if we swap Set namedRng = Range("best_Grade") for Set namedRng = Range(Names("namedRange")) the result might presumably (but not necessarily -- see end of post!) look like:
Set rng = Range("=SUMIF('Ark1'!$B$1:$B$5, "x", 'Ark1'!$A$1:$A$5)")
And of course, this would not work. But throwing namedRange into an Evaluate would, as the other answers demonstrate, be perfectly legal!
Interestingly, if we do ? Evaluate(Names("namedRange")) (omitting the .Value), we get an Error 2015, despite being able to ask the compiler ? Names("namedRange") and get a string in return!

Resources