Meaning of ADDRESS formula arguments - excel

I have to convert this function into VBA and I couldn't understand what the second numbers after the comma inside the ADDRESS() meant. The function is used to calculate time difference between two systems. I know that ADDRESS() can get optional parameters of numbers from 1 to 4, but I don't think this isn't the case here. Can you please help me understand it?
IF(Z44<>"N/R",((INDIRECT(ADDRESS(Y44,1))-INDIRECT(ADDRESS(Z44,1)))*86400)+((INDIRECT(ADDRESS(Y44,6))-INDIRECT(ADDRESS(Z44,6)))*86400),"N/R")

Please, try the next VBA code, able to convert the formula you show. Select a cell and run the code. It will return exactly what the formula does:
Sub testVBAFromFormula()
'=IF(Z44<>"N/R",((INDIRECT(ADDRESS(Y44,1))-INDIRECT(ADDRESS(Z44,1)))*86400)+((INDIRECT(ADDRESS(Y44,6))-INDIRECT(ADDRESS(Z44,6)))*86400),"N/R")
Dim sh As Worksheet, cel As Range
Set sh = ActiveSheet
Set cel = ActiveCell
If sh.Range("Z44").Value <> "N/R" Then
cel.Value = (sh.Range("A" & sh.Range("Y44").Value).Value - sh.Range("A" & sh.Range("Z44").Value).Value) * 86400 + _
(sh.Range("F" & sh.Range("Y44").Value).Value - sh.Range("F" & sh.Range("Z44").Value).Value) * 86400
Else
cel.Value = "N/R"
End If
End Sub
If you split the formula in small pieces you can better understand what happens:
"=ADDRESS(Y44,1)" returns "A" & the number in "Y44", let us imagine 23. "A" is the first column, defined by the second parameter 1.
"=INDIRECT(ADDRESS(Y44,1))" returns the value from "A23".
The same for the second part of the formula, but the second parameter is 16, which means the sixth column: "F".
The rest of the code should now be easily understood, I think...

Related

Subtracting a cell value with all other cells and finding largest value

I have the above list of values. I want to first subtract first value with all other values. After that subtracting second value with all others and so on. Final result should be largest subtraction value and two cells which generated the largest subtraction value.
If you need a VBA solution, try the next code, please. Basically it adapts the formula suggestions made above by #Tom Sharpe:
Sub testLargestSubtraction()
Dim sh As Worksheet, lastRow As Long, rng As Range, maxSubstrVal As Double
Dim maxCellAddress As String, minCellAddress As String, rngMaxS As Range
Set sh = ActiveSheet ' use here your sheet
lastRow = sh.Range("A" & rows.count).End(xlUp).row
Set rng = sh.Range("A2:A" & lastRow)
maxSubstrVal = WorksheetFunction.Max(rng) - WorksheetFunction.Min(rng)
maxCellAddress = "A" & WorksheetFunction.Match(WorksheetFunction.Max(rng), rng, 0) + rng.cells(1).row - 1
minCellAddress = "A" & WorksheetFunction.Match(WorksheetFunction.Min(rng), rng, 0) + rng.cells(1).row - 1
Debug.Print maxSubstrVal, maxCellAddress, minCellAddress
Set rngMaxS = Union(sh.Range(maxCellAddress), sh.Range(minCellAddress))
rngMaxS.Select
End Sub
It returns (in Immediate Window) what you asked for and also selects the two cells which produces the largest subtraction result, independent of the range sorting.
If understand your question as wanting to find the largest difference between any of your numbers, the answer is simply
Max(numbers)-Min(numbers)
Making the simplest assumption, that there are six numbers and they are sorted into descending order, the answers are:
457.05-112.3 => 344.75 , maximum at A1, minimum at A6.
by inspection.
More generally, if you have a variable number of numbers, not sorted, the largest difference is:
=MAX(A:A)-MIN(A:A)
The largest value is at:
=MATCH(MAX(A:A),A:A,0)
And the smallest value at:
=MATCH(MIN(A:A),A:A,0)
You can create a matrix to compare all the possible pairs of numbers, but the answer will be the same. This would be only be necessary if you wanted to find the second largest, third largest difference etc.

Any ideas why VBA isn't being case-sensitive in a VLookup?

I've created a VBA Macro to look at a string of input text in the cell E3, split it into individual characters and then VLookup those characters against a table of individual character pixel widths, which is added to the code using a named range, "pw_Table".
The pixel-widths for each letter are then summed and displayed in a cell below the text input box - "Cells(4,5)". Hitting return is meant to show the combined pixel-width total for the complete string.
The problem is that it is not being case sensitive and is using the same VLookup value for both upper and lower case characters.
All the manuals I've seen say VBA is case sensitive on VLookup, and all I can find are ways to get around this.
For my issue, however, the VLookup must be case sensitive to make sure I get the correct pixel width for each letter, for example, "c" is 9 pixels wide, "C" is 13.
I have tried reordering the upper and lower case characters in the table to see if that made a difference, but it only uses the first values it encounters for each letter of the alphabet, whether they be upper- or lower-case.
I thought that I might use INDEX, MATCH, and EXACT, but couldn't see how to implement that in VBA.
This is the Macro code ...
Private Sub ReadCharacter()
cell_value = ThisWorkbook.Sheets("Pixel-widths").Range("E3")
Character_Value = 0
For rep = 1 To Len(cell_value)
Character = Mid(cell_value, rep, 1)
On Error GoTo MyErrorHandler
Character_Value = Application.WorksheetFunction.VLookup(Character, [pw_Table], 2, 0)
Pixel_Width = Pixel_Width + Character_Value
MyErrorHandler:
Character_Value = 10
Resume Next
Next rep
Cells(4, 5) = Pixel_Width
End Sub
I had some issues with numbers, with VBA reporting Run-time Error 1004, but I bodged this by adding an error trap because all the numerals from 0-9 are 10 pixels wide.
I simply can't see why VBA is breaking its own rules.
Vlookup isnt case sensitive.
ive found this function that "simulates" a vlookup case sensitive.
Function CaseVLook(FindValue, TableArray As Range, Optional ColumnID As Integer = 1) As Variant
Dim xCell As Range
Application.Volatile
CaseVLook = "Not Found"
For Each xCell In TableArray.Columns(1).Cells
If xCell = FindValue Then
CaseVLook = xCell.Offset(0, ColumnID - 1)
Exit For
End If
Next
End Function
to use it just call it CaseVLook(F1,A1:C7,3)
more information in here
https://www.extendoffice.com/documents/excel/3449-excel-vlookup-case-sensitive-insensitive.html
good luck
Here's another way...
Character_Value = Evaluate("INDEX(" & Range("pw_Table").Address(, , , True) & _
",MATCH(TRUE,EXACT(INDEX(" & Range("pw_Table").Address(, , , True) & ",0,1),""" & Character & """),0),2)")
Hope this helps!

Excel VBA Sum from Multiple Sheets

I am trying to create a function or functions that can sum daily hours from time cards for each client to come up with the total hours worked per day. Each client has it's own sheet inside of a single workbook.
Currently, I have a function that determines the sheet that goes with the first client (the third sheet in the workbook):
Function FirstSheet()
Application.Volatile
FirstSheet = Sheets(3).Name
End Function
And one to find the last sheet:
Function LastSheet()
Application.Volatile
LastSheet = Sheets(Sheets.Count).Name
End Function
The part that I am having trouble with it getting these to work within the sum function.
=sum(FirstSheet():LastSheet()!A1
That is basically what I want to accomplish. I think the problem is that I don't know how to concatenate it without turning it into a string and it doesn't realize that it is sheet and cell references.
Any help would be greatly appreciated.
So, an example formula would look like this:
=SUM(Sheet2!A1:A5,Sheet3!A1:A5,Sheet4!A1:A5)
That would sum Sheet2-Sheet4, A1:A5 on all sheets.
Is there a reason you need to write the VBA code to do this?
Can't you just enter it as a formula once?
Also, if you're going to the trouble of writing VBA to generate a formula, it may make more sense to just do the sum entirely in VBA code.
If not, try this:
Sub GenerateTheFormula()
Dim x, Formula
Formula = "=SUM(" 'Formula begins with =SUM(
For x = 3 To Sheets.Count
Formula = Formula & Sheets(x).Name & "!A1," 'Add SheetName and Cell and Comma
Next x
Formula = Left(Formula, Len(Formula) - 1) & ")" 'Remove trailing comma and add parenthesis
Range("B1").Formula = Formula 'Where do you want to put this formula?
End Sub
Results:
The functions return strings and not actual worksheets. The Worksheet does not parse strings well. So add a third function that uses the Evaluate function:
Function MySum(rng As Range)
MySum = Application.Caller.Parent.Evaluate("SUM(" & FirstSheet & ":" & LastSheet & "!" & rng.Address & ")")
End Function
Then you would simply call it: MySum(A1)
It uses the other two function you already have created to create a string that can be evaluated as a formula.
I didn't understand ur question completely but As I understood u have different sheets of different clients which contains supoose column 1 date and column 2
contains hours on that particular date wise hours and a final sheet which column1 contains name of client and column 2 contains total hoursPlease try it
Sub countHours()
Dim last_Row As Integer
Dim sum As Double
sum = 0
'Because I know number of client
For i = 1 To 2 'i shows client particular sheet
last_Row = Range("A" & Rows.Count).End(xlUp).Row
Sheets(i).Activate
For j = 2 To last_Row
'In my Excel sheet column 1 contains dates and column 2 contains number of hours
sum = sum + Cells(j, 2)
'MsgBox sum
Next j
'Sheet 3 is my final sheet
ThisWorkbook.Sheets(3).Cells(i + 1, 2).Value = sum
sum = 0
Next i
End Sub
Happy Coding :

Excel - How do programmatically convert 'number stored as Text' to Number?

I'm looking for a simple Excel VBA or formula that can convert an entire row in Excel from 'number stored as Text' to an actual Number for vlookup reasons.
Can anyone point me in the right direction?
Better Approach
You should use INDEX(MATCH) instead of VLOOKUP because VLOOKUP behaves in an unpredictable manner which causes errors, such as the one you're presumably experiencing.
INDEX ( <return array> , MATCH ( <lookup value> , <lookup array> , 0) )
Using 0 as the last argument to MATCH means the match must be exact
Here is some more in-depth information on INDEX(MATCH)-ing
Further
Add zero +0 to convert a value to a number.
This can be (dangerously) extended with IFERROR() to turn non-numeric text into a zero:
=A2+0
=IFERROR(A2+0,0)
For the inverse, you can catenate an empty string &"" to force the value to be a string.
Notes
If 0 is not used as the last argument to MATCH, it will find all sorts of unexpected "matches" .. and worse, it may find a different value even when an exact match is present.
It often makes sense to do some extra work to determine if there are duplicates in the MATCH lookup column, otherwise the first value found will be returned (see example).
Help with MATCH comes from here, notably the matching logic the 3rd argument controls.
This should work if you add it before your vlookup or index/match lines:
Sheets("Sheet1").UsedRange.Value = Sheets("Sheet1").UsedRange.Value
I did find this, but does anyone have a formula as well?
Sub macro()
Range("F:F").Select 'specify the range which suits your purpose
With Selection
Selection.NumberFormat = "General"
.Value = .Value
End With
End Sub
http://www.ozgrid.com/forum/showthread.php?t=64027
Try this:
Sub ConvertToNumber()
Application.ScreenUpdating = False
Dim cl As Range
For Each cl In Selection.Cells
cl.Value = CInt(cl.Value)
Next cl
Application.ScreenUpdating = True
End Sub
To use it, simply select the relevant block of cells with the mouse, and then run the macro (Alt+F8 to bring up the dialogue box). It will go through each cell in the selected range and convert whatever value it holds into a number.
I wrote a custom vlookup function that doesn't care about data formats. Put this into a module in VBA and use = VLOOK instead of = VLOOKUP
Public Function VLook(sValue As String, rDest As Range, iColNo As Integer)
' custom vlookup that's insensitive to data formats
Dim iLastRow As Long
Dim wsDest As Worksheet
Set wsDest = Sheets(rDest.Parent.Name)
iLastRow = wsDest.Range(wsDest.Cells(100000, rDest.Column).Address).End(xlUp).Row
If iLastRow < rDest.Row + rDest.Rows.Count Then
For X = rDest.Column To rDest.Column + rDest.Columns.Count
If wsDest.Cells(100000, X).End(xlUp).Row > iLastRow Then iLastRow = wsDest.Cells(100000, X).End(xlUp).Row
Next X
End If
sValue = UCase(Application.Clean(Trim(sValue)))
For X = rDest.Row To iLastRow
If UCase(Application.Clean(Trim(wsDest.Cells(X, rDest.Column)))) = sValue Then
VLookDM = wsDest.Cells(X, rDest.Column + iColNo - 1)
Exit For
End If
Next X
End Function
The easiest way I can think of is using the built-in function =VALUE(TEXT_TO_CONVERT_TO_STRING).

Search for value in column that matches another column AND a date?

I have data stored in three columns of Excel
Column A: Serial Number
Column B: Date
Column C: Value (e.g. Cost)
I need to look for the Value (Column C) associated with a particular Serial Number (Column A) AND Date (Column B).
So for example, in the screenshot below, if I want to look for the Value associated with Serial number (T455) and Date (Dec 13, 2010), the value should be 8.
The only method I can come up with would be computationally inefficient, because I would go through ALL the cells each time I look for a value.
Is there a method, for example, that would limit the search area for a given serial number?
For example, if I am looking for a value for Serial Number T455, how can I limit the code to search for the date in Rows (6-13) and find the corresponding value in Column C, rather than searching the whole table?
Sub FindValue()
Dim S as String
Dim D as Date
Dim V as Integer
S = T455
D = Dec 13, 2010
for i = 1 to Range("A1").End(xldown).Row
If Range("A" & i) = S And Range("B" & i) < Date - 7 And Range("B" & i) < Date + 7 Then
' This way i search a date range rather than a specific date
V = Range("C" & i).Value
End If
End Sub
I thought of While loops, or Lookup functions, but reached a dead end.
Non-VBA Solution that may be a lot easier and less of a headache.
Column A consists of the formula, for A1 = "=B1&C1"
Cell G1 formula can be seen in formula bar.
UPDATE
Here is a VBA solution that will work faster, but there are some notes based on what you wrote that I am unsure of. Also, see some comments to help your code work more like you want it to.
Sub FindValue()
Dim S As String, D As Date, V As Integer, rngFound As Range, cel As Range
S = "T455" 'needs quotes around the string
D = "Dec 13, 2010" 'needs quotes around the date
Dim wks As Worksheet
Set wks = ActiveSheet
With wks
'always better to AutoFilter than Loop when you can!
.UsedRange.AutoFilter 1, S
.UsedRange.AutoFilter 2, ">" & D - 7, xlAnd, "<" & D + 7
Set rngFound = Intersect(.UsedRange, .Columns(3)).SpecialCells(xlCellTypeVisible)
'the only thing here is if you have a date range _
'you may return more than one result _
'in that case, I don't know what you want to do with all the V's
If Not rngFound Is Nothing Then
For Each cel In rngFound
V = cel.Value
Next
End If
.AutoFilterMode = False
End With
End Sub
If you are willing to entertain a non-VBA solution, then you can use this implementation, which basically uses this formula:
=IFERROR(INDEX(List, MATCH(0, COUNTIF(H1:$H$1, List)+
IF(Category2<>Criteria2, 1, 0)+IF(Category1<>Criteria1, 1, 0), 0)), "")
There are several VBA methods, which really depend on how comfortable you are with the language and how efficient you want your solution to be. Off the top of my head:
1) filter the list with both criteria, then return the relevant value in whatever row is visible (if any)
2) sort your data by those two columns (first by serial, then date), then perform searches (you'd probably want to call built-in functions like MATCH)

Resources