Offset address to be used in dynamic formula - excel

I am trying to identify a cell in excel using VBA which is going to be used to add a dynamic formula.
This is what I have done so far:
STCELL = Sheets("ADMIN").Range("h" & Rows.Count).End(xlUp).Address(False, False)
The above line gives me cell "H16"
Now I need to offset this address. I thought about this:
STCELL1 = Range(" & STCELL & ").Offset(1, 0)
but unfortunately is not working. The results of the STCELL (start cell) should be used in the next line:
Sheets("admin").Range("H" & Rows.Count).End(xlUp).Offset(1, 0).Formula = "=INDEX(Mapping!$D:$F,MATCH(" & STCELL & ",Mapping!$A:$A,0),1)"
the address of STCELL is properly read by VBA in the last line, but I need to offset it since the location of the cell where the formula is going to be applied will keep changing.
So, question is, how can I offset the address I have identified with my first line of code?
Thank you for all your help.

Since it is the Range.Offset property, focus on offsetting a Range, not the address of a Range:
Dim rng As Range
Set rng = Sheets("ADMIN").Range("h" & Rows.Count).End(xlUp)
STCELL = rng.Address(False, False)
STCELL1 = rng.Offset(1).Address(False, False)

Related

formula for array max if Excel VBA

So this is my formula:
ws8.Range("Y2:Y" & lrowWFS).FormulaArray = "=Max(if(x2='New Stock Data'!H:H,'New Stock Data'!G:G))"
Problem is it's returning to {=Max(if(x2='New Stock Data'!H:H,'New Stock Data'!G:G))} in Y3 onwards.
Any idea how to solve?
It should be as simple as to change FormulaArray to Formula. (I haven't tested this), try:
ws8.Range("Y2:Y" & lrowWFS).Formula = "=Max(if(x2='New Stock Data'!H:H,'New Stock Data'!G:G))"
Couple of things. The generic formula looks like this: {=MAX(IF(criteria_range=criteria,value_range))}. So, instead of x2='New Stock Data'!H:H, you want to use: 'New Stock Data'!H:H=x2. Other than that, unlike regular formulas, array formulas assigned to a range do not adjust relative cell references.
E.g. Range("A1:A2").Formula = "=B1" will successively lead to =B1 and =B2, while Range("A1:A2").FormulaArray = "=B1" will lead to 2x =B1.
One solution is to loop through your range and assign the array formulas to each cell individually. E.g.
Dim rng As Range
Dim lrowWFS As Long
lrowWFS = 3
Set rng = ws8.Range("Y2:Y" & lrowWFS)
For Each cell In rng
cell.FormulaArray = "=MAX(IF('New Stock Data'!H:H=" & Cells(cell.Row, "X").Address(False, False) & ",'New Stock Data'!G:G))"
Next cell
A better solution would be to use SUMPRODUCT instead. This avoids the use of an array formula, and thus also the need for a loop.
E.g.:
With rng
.Formula = "=SUMPRODUCT(MAX(('New Stock Data'!H:H=X2)*('New Stock Data'!G:G)))"
End With
More in general, I would advise proper specification of the ranges in the formula. Define first_row and last_row and use something like this:
"=SUMPRODUCT(MAX(('New Stock Data'!H$" & first_row & ":H$" & last_row & "=X2)*('New Stock Data'!G$" & first_row & ":G$" & last_row & ")))"

Using user range input for a formula

I am trying to create a VBA code that will pull the info to the Left (eventually the right) of a Hyphen based on a range and a cell given by the user.
EX:
Result A & Result B are what I am trying to get too.
I've tested everything in my code until this part and it all works. The entire thing works if I physically type in a cell address (i.e $D2 - I will need the column absolute, but the row relative so that it moves with the range selection). I just can't get it to work with the user input of the "Starting" variable. I need it to be user input because this code will be used on sheets set up completely different than this one. There is a good chance I am missing something obvious but I'm not seeing it #_#. Any suggestions?
**Sorry in advance for the long lines of code
Private Sub Seperate_XtoY_Click()
Dim iCol As Long
Dim iCount As Long
Dim i As Long
Dim Smaller As Range
Dim Bigger As Range
Dim Starting As Range
'Get number of columns that you want to insert with a user input box
iCount = InputBox(Prompt:="How many columns you want to add?")
'Get column NUMBER where you want to insert the new column
iCol = InputBox _
(Prompt:= _
"BEFORE which column do you want to add the new column(s)? (Enter the column number i.e A=1, B=2, C=3, etc)")
'loop to insert new column(s)
For i = 1 To iCount
Columns(iCol).EntireColumn.Insert
Next i
'Makes range variable "Starting" equal to the user input of a range (in this case just 1 cell)
Set Starting = Application.InputBox("Select the FIRST cell of the Original Range of #'s", "Obtain Range Object", Type:=8)
'Makes range variable "Smaller" equal to the user input of a range (where the info will actually populate)
Set Smaller = Application.InputBox("Select a range", "Obtain Range Object", Type:=8)
Smaller.Formula = "=IF(ISNUMBER(SEARCH(""½"", & Starting.Address(0, ""$"") &)),""0.5"",IF(ISNUMBER(SEARCH(""¼"",& Starting.Address(0, ""$"") &)),""0.25"",IF(ISNUMBER(SEARCH(""¾"",& Starting.Address(0, ""$"") &)),""0.75"",LEFT( &Starting.Address(0, ""$"")&, FIND(""–"",& Starting.Address(0, ""$"")&)-1))))"
End Sub
It turns out I had the right idea based on my last comment. I did need remove the variable completely out of the quotes (and then restart them), double check the placing of where I put those quotes, and use a different version of the .Address function to make only my column an absolute reference. All the other lines of code from above were all good, it was just the final line that needed to changed. Thank you #BigBen for giving me a push in the right direction. Looking at the program with fresh eyes also helped lol.
Smaller.Formula = "=IF(ISNUMBER(SEARCH(""½""," & Starting.Address(RowAbsolute:=False) & " )),""0.5"",IF(ISNUMBER(SEARCH(""¼"", " & Starting.Address(RowAbsolute:=False) & ")),""0.25"",IF(ISNUMBER(SEARCH(""¾"", " & Starting.Address(RowAbsolute:=False) & " )),""0.75"",LEFT( " & Starting.Address(RowAbsolute:=False) & " , FIND(""–"", " & Starting.Address(RowAbsolute:=False) & ")-1))))"
I also got the Right side function working too if anyone is interested:
Bigger.Formula = "=IF(ISNUMBER(SEARCH(""– ½""," & Starting.Address(RowAbsolute:=False) & ")),""0.5"",IF(ISNUMBER(SEARCH(""– ¼""," & Starting.Address(RowAbsolute:=False) & ")),""0.25"",IF(ISNUMBER(SEARCH(""– ¾""," & Starting.Address(RowAbsolute:=False) & ")),""0.75"",RIGHT(" & Starting.Address(RowAbsolute:=False) & ",LEN(" & Starting.Address(RowAbsolute:=False) & ")-FIND(""– ""," & Starting.Address(RowAbsolute:=False) & ")-1))))"
PLEASE NOTE for anyone who may want to use a variation of my code I used a slightly bigger hyphen than the typical hyphen ("-" vs "–")

Creating a mixed reference named range with VBA

I'm trying to write some VBA that can create a named range if it matches a header. I've managed to achieve this but hit a snag that I can't seem to get to work.
I need the named range to be mixed reference only locking in the column. I've got this to work also but when trying to combine everything it doesn't carry the mixed ref.
Examples -
Sub test()
i = 1
Do Until Cells(1, i) = "Created Date"
i = i + 1
Loop
NR1 = Cells(1, i).Offset(1, 0).Address(False, True)
ActiveWorkbook.Names.Add Name:="Created_Date", RefersTo:=NR1
ActiveWorkbook.Names("Created_Date").Comment = ""
End Sub
The above will set the named range with the required mixed ref but obviously no sheet name -
so my thought was simply use activesheet.range(NR1) like so -
Sub test()
i = 1
Do Until Cells(1, i) = "Created Date"
i = i + 1
Loop
NR1 = Cells(1, i).Offset(1, 0).Address(False, True)
ActiveWorkbook.Names.Add Name:="Created_Date", RefersTo:=ActiveSheet.Range(NR1)
ActiveWorkbook.Names("Created_Date").Comment = ""
End Sub
This does create the named range on the sheet but the references go back to being locked to one cell!
any ideas?
You can use the External argument in the Range.Address property to make the Workbook and Sheet name part of the returned address.
If you put an address into the RefersTo argument, it just takes the string as its value instead of going to the cells or range that the address is pointing at. To fix this interaction, you can add an = in front of the address to make the String into a formula which Excel will evaluate.
So with the following changes, your code should do what you want:
NR1 = Cells(1, i).Offset(1, 0).Address(False, True, External:=True)
ActiveWorkbook.Names.Add Name:="Created_Date", RefersTo:="=" & NR1

Calculate time difference between 2 dates and give outputs in total hours is generating output as #### which is wrong

I am very new to Excel, VBA, Macro. My macro was working fine because I gave a simple formula, for example, D2(column name)-C2(column name) = Total time in HH:MM format new column. But I notice for some output is just #### not sure what is wrong. 1).Column)).Formula = _
"=" & cl.Offset(1, 0).Address(0, 0) & "-" & .Cells(2, col1).Address(0, 0)
cl.Offset(, 1).EntireColumn.NumberFormat = "[hh]:mm"
The issue occurs because your date in J is earier than in I and therefore the result is negative. You can use the ABS() function to get the absolute difference as positive value.
Therefore adjust your formula as below:
.Formula = "=ABS(" & cl.Offset(1, 0).Address(0, 0) & "-" & .Cells(2, col1).Address(0, 0) & ")"
You have an incorrect formula in this line:
.Range(cl.Offset(1, 1), .Cells(lastR, cl.Offset(1, 1).Column)).Formula = _
"=" & cl.Offset(1, 0).Address(0, 0) & "-" & .Cells(**2**, col1).Address(0, 0)
Why .Cells(2, col1)? This is always giving you row2 of column 1.
Also, after this line:
If cl.Value = "Full Out Gate at Inland or Interim Point (Destination)_recvd"
Then
Add:
If cl.Offset(0,1).Value = "Response Time" Then Exit For
This will keep you from inserting a new column every time you run the macro.
Try using clear variable names and consistent method for referring to rows and columns.
actCol = col1
recvdCol = cl.Column
responseCol = cl.offset(0,1).Column
.Range(lastR, responseCol).Formula = _
"= Abs(" & .Cells(lastR, recvdCol) & "-" & .Cells(lastR, actCol).Address(0, 0) & ")"
I would use a simpler approach. Highlight the entire table, and click "Format as Table", and be sure to check off "My table has headers." This will give you a named range (default name is Table1, but you can change it). Then, in the Response Time column, simply enter your formula on the first row of the table, but use your mouse to select the cells instead of typing in a cell name like "I2". You will find that the resulting formula includes something like =[#actl]-[#recvd], except that the actl and recvd will be replaced by your actual column names. And, the formula will apply to every row of the table. If you add a new row, the formula will automatically appear in that row. No code needed.
If you have a reason to use code instead of a Table (named ranges), then I would recommend (1) this code be placed directly in the "Main" worksheet module and (2) use use the "Worksheet_Changed" procedure. Microsoft Excel VBA Reference. In this case, any time the
Private Sub Worksheet_Change(ByVal Target As Range)
'Note, Target is the Range of the cell(s) that just changed.
If Intersect(Target, Range("A1:A10")) Is Nothing Or Target.Cells.Count > 1 Then Exit Sub
If ActiveSheet.Cells(1, Target.Column) = "Full Out Gate at Inland or Interim Point (Destination)_actual" Then
' Cell in actual column was modified. Let's set the formula in the Response Time column:
On Error Goto EH
Application.EnableEvents = False
' Add your code here. You'll need to modify it somewhat to accommodate this methodology.
Application.EnableEvents = True
End If
EH:
Application.EnableEvents = True
Err.Raise ' expand this to whatever error you wish to raise
End Sub
Err.Raise help

Excel VBA Find cell address in range based on min to max for where class

Please assist me for following scenario
I need to go thorough one range and find Minimum value.If corresponding value in another range matches, then I need to find column number.
I am able to do with following code; however when there is more than one minimum value, following code always give fist minimum value column number. it is not moving to next minimum value column even if condition is not met.
it is kind of where class I am trying to apply
MyOrder = 1
Do Until wksSkill.Cells(MyRow, MyColNum).Value <> "Exclude"
MyColNum = Application.Evaluate("=CELL(""col"", INDEX(" & MyColRange.Address(0, 0) & ", MATCH(SMALL(" & MyColRange.Address(0, 0) & ", " & MyOrder & " ), " & MyColRange.Address(0, 0) & ", 0)))")
MyOrder = MyOrder + 1
Loop
First "MyColNum" value passed from another if statement, then it will take the function output. It works till the range has one minimum value.
Please assist me for any other alternative
Ok, so what I can propose, is to find min value in range, and then loop through every column in that range and check if this min value occurs there and if value "Exclude" occurs in MyRow. I have some example values in my code:
Sub mac()
Dim minVal As Double
Dim MyColRange As Range, rng As Range
Dim wksSkill As Worksheet
MyRow = 6
Set wksSkill = Sheets("Arkusz1")
Set MyColRange = wksSkill.Range("A1:E5")
minVal = Application.WorksheetFunction.Min(MyColRange)
For Each rng In MyColRange.Columns
If Not IsError(Application.Match(minVal, rng, 0)) Then
If wksSkill.Cells(MyRow, rng.Column) = "Exclude" Then
MsgBox "Column " & rng.Column
End If
End If
Next rng
End Sub

Resources