Dynamic formula autofill - excel

I would like to know how may i convert this code into dynamic range autofill for the column I to enable the freedom of editing the excel sheet at a later time without the need to adjust the vba code.
Sub Rowcount()
'Charles, M
Dim H As Long
Set sh = Worksheets("Report-Charles, M")
H = sh.UsedRange.Rows.Count
Range("I2:I" & H).Formula = "=IF((AND(OR(E2=""Unrated"",E2=""""),OR(G2<>""Unrated"",G2<>""""))),G2,IF(E2>=""4,25"",""High Performance"",IF(E2<""3,35"",""Low Performance"",IF(AND(E2>=""3,35"",E2<""4,25""),""Medium Performance"",""Unrated""))))"
MsgBox (H) & "Rows have been Autofilled with 3 scale Rating Results"
End Sub

Have a look into the AutoFill function:
Range("I2:I" & H).AutoFill Destination:=Range("I2:I2000"), Type:=xlFillDefault

First off, you are only implicitly referencing the Report-Charles, M as the ActiveSheet property to put the .Formula into; not explicitly with direct reference.
Second, To assign the formula, use a direct .Formula write, the Range.AutoFill method or the Range.FillDown method.
Lastly, writing a formula .Formula through VBA should be done with EN-US syntax and regional settings. If you want to use non-EN-US regional settings like 3,35 or 4,25 then use the Range.FormulaLocal property.
Above all else, treat numbers as numbers; not as text-that-look-like-numbers.
with Worksheets("Report-Charles, M")
h = .UsedRange.Rows.Count
.Range("I2:I" & H).FormulaLocal = _
"=IF((AND(OR(E2=""Unrated"", E2=TEXT(,)), OR(G2<>""Unrated"", G2<>TEXT(,)))), G2, IF(E2>=4,25, ""High Performance"", IF(E2<3,35, ""Low Performance"", ""Medium Performance"")))"
.Range("I2:I" & H).Formula = _
"=IF((AND(OR(E2=""Unrated"", E2=TEXT(,)), OR(G2<>""Unrated"", G2<>TEXT(,)))), G2, IF(E2>=4.25, ""High Performance"", IF(E2<3.35, ""Low Performance"", ""Medium Performance"")))"
end with
with Worksheets("Report-Charles, M")
'any of the following will fill column I with formulas to the last row in .UsedRange
'all of the following assumes a valid formula in I2
h = .UsedRange.Rows.Count
.Range("I2:I" & H).Formula = .Range("I2").Formula
.Range("I2:I" & H).FillDown
.Range("I2:I" & H).DataSeries Rowcol:=xlColumns, Type:=xlAutoFill
.Range("I2").AutoFill Destination:=.Range("I2:I" & H), Type:=xlFillDefault
end with
I've shortened one IF condition since the AND was unnecessary and Medium was the default response. Using TEXT(,) is the same as saying "" and does not have to double-up double-quotes.

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 & ")))"

Compute countif in column Range & combine if with count if

I have two formulas that I need to transfer to VBA.
On Excel, my formula would be =countif(A$2:A2,A2) so I transferred that using this formula but everything is returning to 1. The rows didn't become dynamic and I want only the values to be displayed.
For a = 2 To lrow
ws.Range("T" & a).Formula = "=CountIf(A$2&"":""&A2)"",""&A2)"
Next a
Next formula that I use in Excel is
=IF(COUNTIF(A:A,A2)>Q2,"Check","Ok")
I tried this formula in VBA:
For i = 2 to lrow
If Countif(ws.Range("A2:A" & lrow), "A2") > ws.Range("Q2:Q", & lrow) Then
ws.Range("T" & i).Value = "Check"
Else
ws.Range("T" & i).Value = "Ok"
End If
Next i
You could populate column T with your first formula with this line of code:
ws.Range("T2:T" & lrow).FormulaR1C1 = "=COUNTIF(R2C[-19]:RC[-19],RC[-19])"
I can't advise on your second formula unless you clarify where you want to write it...

Dynamic Column Index Name Error in Formula

I am trying to calculate the component q'ty from Sheet Plan to Sheet Result by using Vlookup to fill in column,having:
Count_col: is the total column in sheet Plan
Last_col: is the total column in sheet Result (before add column Demand)
Sheet Results
Material
Component
Demand W1
Demand W2
ABCD1000
nc200
#NAME?
#NAME?
Sheet Plan
Material
Demand W1
Demand W2
ABCD1000
1000
200
For i = 1 To count_col
Cells(1, i + last_col).Value = "=Plan!RC[-2]"
Cells(1, i + last_col).Offset(1, 0).Select
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC1,Plan!C1:C15,i+1,0)"
Next i
But the result is name error, I checked the spelling of function is correct and dont know how to fix. Why there is "#" in my formula?
Detail of error
=VLOOKUP($A2,Plan!$A:$O,#i+1,0)
i+1 inside "" behaves like a string rather than a variable. Try this.
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC1,Plan!C1:C15," & i + 1 & ",0)"
Also avoid the use of .Select. Your code can be written as
Cells(1, i + last_col).Offset(1, 0).FormulaR1C1 = _
"=VLOOKUP(RC1,Plan!C1:C15," & i + 1 & ",0)"
Recommended Reading: How to avoid using Select in Excel VBA
Also you are mixing R1C1 and A1 style of referencing. I would recommend using one of them. A simple Google search R1C1 vs A1 style will explain what they are.
In R1C1, Plan!C1:C15 needs to be written as Plan!R1C3:R15C3. So your final code would be
Cells(1, i + last_col).Offset(1, 0).FormulaR1C1 = _
"=VLOOKUP(RC1,Plan!R1C3:R15C3," & i + 1 & ",0)"

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

Translate a worksheet formula in VBA

Can somebody help me to write this formula in excel VBA?
=IF(ISERROR(VLOOKUP(A3,Temp!$A$3:$A$595,1,FALSE)),A3,"0")
My code is getting stuck with :"syntax error"
Sub checkDuplitems()
Application.ScreenUpdating = False
Const top As Integer = 3
Dim bottom As Long
bottom = Sheets("Temp").Cells(Rows.Count, top).End(xlUp).row
With ThisWorkbook.Sheets("trash").Range("A" & top & ":A" & bottom)
.Formula = "=IF(ISERROR(VLOOKUP(A" & top & ",Temp!$B$" & top & ":$B$" & bottom & _
",1,FALSE)),A" & top & ", & '" 0" & ," '")"
.Value = .Value
.SortSpecial
End With
'Call something...
End Sub
You have a concatenation problem in the second line of the .Formula line.
To emulate the formula you have at the top of your question (which is wrong incidentally because you should be pointing to $B$3:$B$595 or something like that because your look up cell A3 should not be inside the VLOOKUP range).
Try this new .Formula line:-
.Formula = "=IF(ISERROR(VLOOKUP(A" & top & ",Temp!$B$" & top & ":$B$" & bottom & _
",1,FALSE)),A" & top & ", " & "0)"
Are you sure you want to use top as both the starting row in column A and the column to get the bottom row from the Temp worksheet? The important column on the Temp worksheet is column B (i.e. 2) not C (i.e. 3).
If you are putting formula(s) into Trash!A3:A595 that reference Trash!A3:A595 then these are circular references and cannot be resolved under normal conditions. I'll put the formulas into column Z.
If you are operating with Excel 2007 or newer then I would humbly propose this alternate that uses the worksheet's IFERROR function and does not attempt to make text out of the 0 returned value.
Const top As Integer = 3
Dim bottom As Long
bottom = Sheets("Temp").Cells(Rows.Count, "B").End(xlUp).Row '<~~change here
With ThisWorkbook.Sheets("trash")
With .Range("Z" & top, .Cells(Rows.Count, "A").End(xlUp).Offset(0, 25))
.Formula = "=IFERROR(VLOOKUP(A" & top & ", Temp!$B$" & top & ":$B$" & bottom & _
", 1, FALSE), 0)" '<~~ big change here
.Value = .Value
End With
End With
It is also curious as to why the number of rows of formulas in the Trash worksheet must be governed by the number of rows of data in the Temp worksheet. I would have thought that the number of values in column A of the Trash sheet should govern how many formulas go into the Trash worksheet.

Resources