Using autofill with a MAX function within a macro - vba

I know you've answered similar topics which I have tried to duplicate, but I am a novice and apparently need the answer spelled out for me! I am trying to apply autofill code to a MAX formula column within a Macro, so that it will autofill to different row counts each time.
Range("AC2").Select
ActiveCell.FormulaR1C1 = "=MAX(RC[-2],RC[-1])"
Selection.AutoFill Destination:=Range("AC2:AC285")
Range("AC2:AC285").Select
Thank you!

It is only important to fill the formula down to the last value within the columns referenced within the formula.
dim lr as long
with worksheets("sheet1")
lr = application.max(.cells(.rows.count, "AA").end(xlup).row, _
.cells(.rows.count, "AB").end(xlup).row)
.Range("AC2:AC" & lr).FormulaR1C1 = "=MAX(RC[-2],RC[-1])"
end with

Assuming there are no blanks between the first and last row in column AC this will work and you don't even need AutoFill
With Range(Range("AC2"),Range("AC2").End(xlDown))
.FormulaR1C1 = "=MAX(RC[-2],RC[-1])"
End With
This works specifically becuase you are using R1C1 notation which can be applied across all cells.
If there may be blanks, you can find last row like below and fill the formulas the same way:
Dim lastRow as Long
lastRow = Range("AC" & Rows.Count).End(xlUp).Row
With Range("AC2:AC" & lastRow)
.FormulaR1C1 = "=MAX(RC[-2],RC[-1])"
End With

So you have two main tasks:
how to define last row in a given column;
how to define range, based on a row and column;
This is the answer both:
Option Explicit
Sub TestMe()
Dim currLastRow As Long
currLastRow = lastRow(columnToCheck:=4)
With Worksheets(1)
.Range("D1").FormulaR1C1 = "=MAX(RC[-2],RC[-1])"
.Range("D1").AutoFill Destination:=.Range(.Cells(1, "D"), .Cells(currLastRow, "D"))
End With
End Sub
Function lastRow(Optional wsName As String, Optional columnToCheck As Long = 1) As Long
Dim ws As Worksheet
If wsName = vbNullString Then
Set ws = ActiveSheet
Else
Set ws = Worksheets(wsName)
End If
lastRow = ws.Cells(ws.Rows.Count, columnToCheck).End(xlUp).Row
End Function
The lastRow function gives the last row per column. In your case, you want column D, e.g. the 4. column.

Related

Delete empty rows of a table

Hello I want to delete empty rows of a table and i am finding issues.
Dim rng As Range
rng = Sheets("NewForecast").ListObjects("Table").Range.Select
If rng.Rows = 0 Then
rng.EntireRow.Delete
End If
I don't know how to write it, I tried several ways, looked for here, but could not find an specific solution. I want delete if the Row is completely empty. Any help much appreciated!
I managed to work on that! Thanks for all who actually opened my mind. Look below, it is simple and doing what I want, macro goes faster too.
Range("Table[#Headers]").Select
Selection.AutoFilter
ActiveSheet.ListObjects("Table").Range.AutoFilter Field:=2, Criteria1:="="
Range("Table").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.EntireRow.Delete
Range("Table[#Headers]").Select
ActiveSheet.ShowAllData
Try something like
Dim ws as Worksheet
Set ws = ActiveWorkbook.Worksheets("SHEET NAME HERE")
Dim lRow as long
Dim rng as range
lRow = ws.Range("A" & Rows.Count).end(xlUp).row
'Assuming your table starts in column A, put in start/end row numbers
For each rng in ws.Range("A1:A" & lRow)
If ws.Range("A" & rng.row) = vbNullString then
ws.Rows(rng.row).Delete
End if
Next rng
When trying to delete rows in a sheet, always use a backward For loop (For i = 100 to 1 Step -1 for instance).
When checking if a certain Range or Row is completely empty, the WorksheetFunction.CountA comes in quite handy.
Option Explicit
Sub DeleteEmptyRows()
Dim Rng As Range
Dim LastRow As Long
Dim lRow As Long
With Sheets("NewForecast")
Set Rng = .ListObjects("Table").Range
' find last row in "Table"
LastRow = .ListObjects("Table").Range.Rows.Count
' loop through all "Table" rows, loop backwards when deleting
For lRow = LastRow To 2 Step -1
' use CountA to check if entire row is empty
If WorksheetFunction.CountA(.Rows(lRow)) = 0 Then
.Rows(lRow).EntireRow.Delete
End If
Next
End With
End Sub
This is possible without looping.
Filter the table so the values showing are the ones you want to delete
Find the first "deletable" row (where cell.value = "") in the last column of the sheet (will most typically be blank, most people don't use the last column),
Then find the last "deletable" row (where cell.value = "").
Then use this:
Rows(firstRow & ":" & lastRow).EntireRow.Delete
This can be expensive (take a long time) if your field of values is very large but works on sheets as well as tables and is faster (better) than looping.

using a formula in vba to compare cells and enter results in another cell

I going to use a formula in VBA to compare to columns of data and if a match is found then enter some data from one sheet to another. I have used a formula on the first row and this works I get the desired results, I want to automate it as this will be part of other automations on the report. I have got some code which enters a column heading then applies the sumif function to the entire column but I get the same results all the way down, it is the results for the first row.
Code
Sub ImportCosting()
Dim z As Workbook
Dim x As Workbook
Set x = Workbooks.Open("C:\Documents\Reports\MEP.xlsx")
With Workbooks("MEP")
Worksheets("DynamicReport").Range("P5").Value = "Budget"
Worksheets("DynamicReport").Range("Q5").Value = "Forecast"
End With
Set z = Workbooks.Open("C:\Documents\Reports\Budget.xlsx")
With x.Worksheets("DynamicReport")
lastRow = .Cells(Rows.Count, 5).End(xlUp).Row
For Each rng In .Range("P6:P" & lastRow)
rng.Formula = "=SUMIF('[Budget.xlsx]DynamicReport'!$C:$C,$B6,'[Budget.xlsx]DynamicReport'!H:H)"
rng.Value = rng.Value
Next rng
End With
End sub
Hope I have explained the problem correctly. Can anyone tell me where I have gone wrong and how to get it so that the sumif function is applied to each row and not the results for the first row repeated.
Thanks
I am not sure but I guess you want to change the B6 to the rng.row
I guess you are getting the same result in every cell of rng because you are putting B6 as the criteria for sum so change that to the corresponding row number in the B column so that you get the desired result.
Change this:
rng.Formula = "=SUMIF('[Budget.xlsx]DynamicReport'!$C:$C,$B6,'[Budget.xlsx]DynamicReport'!H:H)"
to this
rng.Formula = "=SUMIF('[Budget.xlsx]DynamicReport'!$C:$C,$B" & rng.Row & ",'[Budget.xlsx]DynamicReport'!H:H)"
pls try below
Sub ImportCosting()
Dim z As Workbook
Dim x As Workbook
Set x = Workbooks.Open("C:\Documents\Reports\MEP.xlsx")
With Workbooks("Bank.xlsx")
Worksheets("DynamicReport").Range("P5").Value = "Budget"
Worksheets("DynamicReport").Range("Q5").Value = "Forecast"
End With
Set z = Workbooks.Open("C:\Documents\Reports\Budget.xlsx")
With x.Worksheets("DynamicReport")
lastRow = .Cells(Rows.Count, 5).End(xlUp).Row '"E"
For Each Rng In .Range("P6:P" & lastRow)
Rng.Formula = "=SUMIF([Budget.xlsx]DynamicReport!$C:$C,[Budget.xlsx]DynamicReport!$B$" & Rng.Row & ",[Budget.xlsx]DynamicReport!H:H)"
'Rng.Value = Application.WorksheetFunction.SumIf(z.Worksheets("DynamicReport").Range("C:C"), z.Worksheets("DynamicReport").Range("B" & Rng.row), z.Worksheets("DynamicReport").Range("H:H"))
Rng.Value = Rng.Value
Next Rng
End With
End Sub

Looping through ranges in a column

I have a sheet with with orders and a timestamp.
I want to sort these rows based on the timestamp in the column on the right, but I want to keep their grouping position kind of. Like I want the 4 first rows to be sorted but stay in the 4 first row, then I want to sort row 8 and 9, but have them stay there.
I have managed to select both ranges, and leave out the "middle", but the .sort method will not work unless the key cells are in one range. So I thought maybe if I loop through the different ranges in the column or something like that.
Here is the code I have for now, thought I don't think it will make a difference.
Dim LR As Long, cell As Range, rng As Range
With Sheets("Ark1")
Dim start As Range
Set start = Range("N16")
LR = .Range("N" & Rows.Count).End(xlUp).Row
For Each cell In .Range("N16:N" & LR)
If cell.value <> "" Then
If rng Is Nothing Then
Set rng = cell
Else
Set rng = Union(rng, cell)
End If
End If
Next cell
rng.Sort key1:=start, order1:=xlAscending, Header:=xlGuess
End With
Well, the easiest way to achieve your goal is to re-numerate the rows in a custom order. For example you assign number #1 to the first groups of the rows, #2 to the second and so on. Then you just sort all the range by two columns, first would be your custom "order" and the second timestamp. :)
Assuming that each block is separated by blank values in column N, and that you want to sort the whole rows for each blocks, here is the code I suggest:
Public Sub testSort()
Dim firstRow As Long
Dim lastRow As Long
Dim blockStart As Long
Dim blockEnd As Long
Dim rng As Range
firstRow = 3
lastRow = Cells(Rows.Count, 14).End(xlUp).Row
blockStart = firstRow
Do
If Cells(blockStart + 1, 14) <> "" Then
blockEnd = Cells(blockStart, 14).End(xlDown).Row
Else
blockEnd = blockStart
End If
Set rng = Range(Rows(blockStart), Rows(blockEnd))
rng.Sort Key1:=rng.Cells(, 14), Order1:=xlAscending, Header:=xlNo
blockStart = Cells(blockEnd, 14).End(xlDown).Row
Loop Until blockEnd >= lastRow
End Sub

Row Number reference with VBA

I have searched a bit for a VBA code that will list me a row reference and am not finding results. Perhaps I am missing what the actual term for it is?
I have a list of names in Column A, starting at A2. Then what I would like is a listing of 1,2,3,4,5 going down Column B, starting from B2, until the names stop.
I can do this as a formula but need to have the values set there by a macro in this case.
Can this be done?
If I understand you correctly then this should work:
Sub test()
Dim lastRow As Long, counter As Long
Dim cell As Range
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("NAME_OF_YOUR_WORKSHEET")
lastRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
counter = 1
For Each cell In ws.Range("B2:B" & lastRow)
cell.Value = counter
counter = counter + 1
Next cell
End Sub
No need for a loop:
Sub NumberRows()
With Sheets("Sheet Name Here")
With .Range("B2:B" & .Cells(.Rows.Count, 1).End(xlUp).Row)
.Formula = "=ROW()-1"
.Value = .Value
End With
End With
End Sub

Select last cell in a column with blanks

I am trying to find the last cell in a column that is populated with data in VBA. The problem is, in the range, there are blank cells. Is there any way to select the last cell with data if there are blanks? Any help would be greatly appreciated! I have pasted my range definitions below.
If Range("BL2") <> "" Or Range("BM2") <> "" Then
Set usr11 = Range("BL:BL")
Set usr12 = Range("BM:BM")
I'm not sure if this is what you're looking for
This is what I use to get the last row; just give it a column and a sheet.
Function getLastRow(sheet As String, Col As Variant) As Integer
getLastRow = Sheets(sheet).Cells(Sheets(sheet).Rows.Count, Col).End(xlUp).row
End Function
Then you can use it like this:
Range("A" & getLastRow(ActiveSheet,"A")).Select 'Select the last row in column A
Similar function to get the last column with data:
Function getLastCol(sheet As String, row As Variant) As Integer
getLastCol = Sheets(sheet).Cells(row, Sheets(sheet).Columns.Count).End(xlToLeft).Column
End Function
Using Find
This will work on the ActiveSheet
Dim lngLastRow as Long
'If column is A
lngLastRow = Columns(1).Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
This will work for you
Sub SelectBlank()
Dim lastRow As Long: lastRow = Range("A1").End(xlDown).Row 'change to whatever column you have
Dim i As Long
For i = 1 To lastRow
If Range("A" & i).Value = "" Then
Range("A" & i).Select
Exit For
End If
Next i
End Sub