Excel VBA - Finding Last Non-Empty Row Based on Column Header - vba

I am currently creating a reporting sheet for equipment for our company. This sheet will grab data from multiple Excel sheets and populate it based on our custom report template. So far I have managed to find on how to merge multiple sheets and find the column header. But now I'm stucked on how to find the last non empty value based on column header.
Attached in the picture above is the sample data. As you can see, the last non empty cell in each row is the average of the row. What I am trying to do is to find the header column(eg SVC525) and take the last non empty value of the column, which is average.

for the example given, column B, this should do the trick
Dim lastrow as Integer, val
lastrow = Range("B" & Rows.Count).End(xlUp).Row
val = range("B" & lastrow + 2).Value
to iterate through your rows(header) that is not empty is another story that you can easily search for.

you may be after something like this
Dim svVal As String
svVal = "SVC525" '<--| set your header value to be searched for in row 1
With Worksheets("averages") '<--| change "Averages" tou your actual sheet name
MsgBox .Cells(.Rows.count, .Range("A1", .Cells(1, .Columns.count).End(xlToLeft)).Find(what:=svVal, LookIn:=xlValues, lookat:=xlWhole).column).End(xlUp)
End With

Related

Unsure How to Dynamically Paste a Formula To Last Column and Last Row

VBA question using Excel 2016 (64 bit)
I have header data in the first two columns (A:B) and the top row (1). I would like to dynamically paste a formula downward, starting from cell C2, to the last row and the last column. The working prototype is as follows:
Dim LstCol As Long
LstCol = Cells(1, Columns.Count).End(xlToLeft).Column
Range(Cells(2, "C"), Cells(2, LstCol)).Value = "=INDEX(RC1,MATCH(R1C,RC2,0))"
Dim LstRow As Long
LstRow = Cells(1, Rows.Count).End(xlUp).Row
Range(Cells(2, "C"), Cells(2, LstRow)).Value = "=INDEX(RC1,MATCH(RC1,R2C,0))"
The first Dim works as intended. The formula is successfully deployed throughout the second row to the final column (or perhaps it starts at the last column and moves leftward). However, the second Dim stops on an error. I'm unsure how to spread the data from the last row (to the last column) upwards to the second row (and the corresponding last column).
In my example, the first two columns have header data from 1 to 5330 (A1:B5330). I also have header data in the first row (C1:AX1). My target is to fill the formula =INDEX($A2,MATCH(D$1,$B2,0)) from C2:AX5330 dynamically.
Where am I going wrong?
You need to properly qualify your instances of Range and Cells with a worksheet. You can either directly do this, dim a worksheet variable, or use a With block like so:
Dim LRow as Long
With ThisworkBook.Sheets("????")
LRow = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("C2:AX5330").Formula = "=INDEX($A2,MATCH(D$1,$B2,0))" 'Make sure your cell references are correct here
.Range("C2:AX5330").Value = .Range("C2:AX55330").Value 'Place as values instead of formula
End With

Count the number of cells in a found column using VBA

I am pretty new to VBA and I have been fighting with creating one simple report for many days so I decided to inquire for some help. I will be really grateful for any tips you have or could point to any errors I might've made in my code.
I have the below piece of code (extracted from my loop). What I want to do is to create a list based on around 20 excel files that will have below stats:
name of the current tab inside the workbook
count of nonblanks in a column which name contains word "Difference" (always in row 7 but can be in different columns)
count from the same column but where cells are not blank AND different than 0.
For the last stat I didn't even start so you won't see it in my code but I would appreciate if you have any tips for this one too (which method best to use).
Windows("PassRate.xlsm").Activate
b = ActiveSheet.Cells(Rows.count, 2).End(xlUp).Row + 1
Cells(b, 3) = xlWorkBook.Worksheets(i).Name
xlWorkBook.Worksheets(i).Activate
Set Myrng = Range("B7:M9999").Find(What:="Difference", LookAt:=xlPart, SearchOrder:=xlByColumns, MatchCase:=False)
If Not Myrng Is Nothing Then
RowQnt = xlWorkBook.Worksheets(i).Myrng.Offset(9999, 2).Cells.SpecialCells(xlCellTypeConstants).count
End If
Windows("PassRate.xlsm").Activate
Cells(b, 4) = RowQnt
My problem is that the macro runs and works, but the result I get is the list of tab names but all counts are 0 and I cannot overcome this issue. For the line number 7 I've also tried the piece of code below which yields the same result.
RowQnt = xlWorkBook.Cells(Rows.count, Myrng).End(xlUp)
Is it possible that my problem is due to the fact that in the source files the column containing word "Difference" is sometimes two merged columns? Unfortunately, I cannot change that as these are some automatically generated files from another program.
xlWorkBook.Worksheets(i).Myrng isn't a valid Range syntax while you can simply use MyRng which you already set to a not null Range reference and already has both parent worksheet and workbook references inside it
but even Myrng.Offset(9999, 2).Cells wouldn't do since it references one cell only and not a range of cells
you need a Range(Range1, Range2) syntax, where both Range1 and Range2 are valid Range references to the first and last cell of the range you actually want to count not blank cells of
furthermore you could use WorksheetFunction.CountA() function instead of SpecialCells(xlCellTypeConstants) range, since this latter errors out if no constant cells are found in the range it's being applied to (so you'd need a check) while the former simply returns zero if no not empty cells are found
for all what above you could write the following GetRowQnt() function:
Function GetRowQnt(sht As Worksheet) As Long
Dim Myrng As Range
With sht '<--| reference passed worksheet
Set Myrng = .Rows(7).Find(What:="Difference", LookAt:=xlPart, SearchOrder:=xlByColumns, MatchCase:=False) '<--| find "Difference" in its 7th row
If Not Myrng Is Nothing Then GetRowQnt = WorksheetFunction.CountA(.Range(.Cells(8, Myrng.Column), .Cells(WorksheetFunction.Max(.Cells(.Rows.count, Myrng.Column).End(xlUp).row, 8), Myrng.Column))) '<--| count not blank cells in column where "Difference" was found from row 8 down to its last not empty cell
End With
End Function
and use it in your main code as follows:
With Windows("PassRate.xlsm").ActiveSheet '<--| reference "PassRate.xlsm" workbook active sheet (or change 'ActiveSheet' with 'Worksheetes("yourSheetName")')
For i = 1 To xlWorkbook.Worksheets.count '<--| loop through 'xlWorkbook' workbook worksheets
b = .Cells(.Rows.count, 3).End(xlUp).row + 1 '<--| get "PassRate.xlsm" workbook active sheet current first empty cell in column "C"
.Cells(b, 3) = xlWorkbook.Worksheets(i).Name
.Cells(b, 4) = GetRowQnt(xlWorkbook.Worksheets(i))
Next
End With
please note that with
b = .Cells(.Rows.count, 3).End(xlUp).row + 1
I took column "C" as the leading one to get last not empty row from, since there was no code in your post that wrote something in column "B".
But if your real code has some
.Cells(b, 2) = somedata '<--| write something in column "B" current row
then you can go back to b = .Cells(.Rows.count, 2).End(xlUp).row + 1

VBA Subroutine to fill formula down column

I have a current Sub that organizes data certain way for me and even enters a formula within the first row of the worksheet, but I am running into the issue of wanting it to be able to adjust how far down to fill the formula based on an adjacent column's empty/not empty status. For example, each time I run a report, I will get an unpredictable amount of returned records that will fill out rows in column A, however, since I want to extract strings from those returned records into different Columns, I have to enter formulas for each iteration within the next three columns (B, C, and D). Is there a way to insert a line that will evaluate the number of rows in Column A that are not blank, and then fill out the formulas in Columns B, C, and D to that final row? (I know that tables will do this automatically once information is entered in the first row, but for logistical reasons, I cannot use tables).
My current code that fills out the formula in Column B, Row 2 is:
Range("B2").Select
ActiveCell.FormulaR1C1 = "=MID(RC[-1],FIND(""By:"",RC[-1])+3,22)"
Thanks!
The formula that you actually need is
=IF(A2="","",MID(A2,FIND("By:",A2)+3,22))
instead of
=MID(A2,FIND("By:",A2)+3,22) '"=MID(RC[-1],FIND(""By:"",RC[-1])+3,22)"
This checks if there is anything in cell A and then act "accordingly"
Also Excel allows you to enter formula in a range in one go. So if you want the formula to go into cells say, A1:A10, then you can use this
Range("A1:A10").Formula = "=IF(A2="","",MID(A2,FIND("By:",A2)+3,22))"
Now how do we determine that 10? i.e the Last row. Simple
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long
'~~> Change the name of the sheet as applicable
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
'~~> Find Last Row in Col A
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("B2:B" & lRow).Formula = "=IF(A2="""","""",MID(A2,FIND(""By:"",A2)+3,22))"
End With
End Sub
More About How To Find Last Row
You can use this to populate columns B:D based on Column A
Range("B2:D" & Range("A" & Rows.Count).End(xlUp).Row).Formula = _
"=MID($A2,FIND(""By:"",$A2)+3,22)"

I need a VBA code to count the number rows, which varies from ss to ss, return that number and copy and paste that row and all other columns

I have vba question I have been trying to find the answer for for a long time. I have numerous spreadsheets from numerous clients that I run macro's on, I'm new to coding and have been able to mostly figure out what I need to do. My clients send us data monthly and every month the number of rows change. The columns don't change but the amount of data does. My previous macro's I have just chosen the entire column to copy and paste onto our companies template. This worked fine for must things but has created some really long code and macros take a long time. I would like to write a code that counts how many rows are in a certain column and then from there copies and pastes that however many rows it counted in each column. Only a few columns contain data in every row, so I need it to count the rows in one specific column and apply to that every column. Any help would be appreciated.
Thanks
Tony
Hi Guys,
Still having issues with this, below I pasted the code I'm using if anyone can see why it won't run please help.
Windows("mmuworking2.xlsx").Activate
Workbooks.Open Filename:= _
"C:\Users\I53014\Desktop\QC DOCS\Sample_Data_Import_Template.xlsx"
Windows("mmuworking2.xlsx").Activate
Dim COL As Integer
COL = Range("A:DB").Columns.Select
**Range(Cells(2, COL), Cells(Range("E" & Rows.Count).End(xlUp).Row, COL)).Copy Destination:=Windows("Sample_Data_Import_Template.xlsx").Range("A2")**
Range("A2").Paste
Range("A5000").Formula = "='C:\Users\I53014\Desktop\[Import_Creator.xlsm]sheet1'!$B$2"
ActiveWorkbook.SaveAs Filename:="Range (A5000)", _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
I bolded where it keeps stopping.
This should give you the last row containing data:
ActiveSheet.UsedRange.Rows.Count
This will give you the last row in a specific column:
Range("B" & Rows.Count).End(xlUp).Row
here is an example of how I can copy every row in the first three columns of a worksheet
Sub Example()
Dim LastRow As Long
LastRow = ActiveSheet.UsedRange.Rows.Count
Range(Cells(1, 1), Cells(LastRow, 3)).Copy Destination:=Sheet2.Range("A1")
End Sub
You have to be careful as there are some caveats to both methods.
ActiveSheet.UsedRange may include cells that do not have any data if the cells were not cleaned up properly.
Range("A" & Rows.Count).End(xlUp).Row will only return the number of rows in the specified column.
Rows(Rows.Count).End(xlUp).Row will only return the number of rows in the first column.
Edit Added an example
Edit2 Changed the example to be a bit more clear
For this example lets say we have this data
You could copy any other column down to the number of rows in column A using this method:
Sub Example()
Dim Col as Integer
Col = Columns("C:C").Column
'This would copy all data from C1 to C5
'Cells(1, Col) = Cell C1, because C1 is row 1 column 3
Range(Cells(1, Col), Cells(Range("A" & Rows.Count).End(xlUp).Row, Col)).Copy Destination:=Sheet2.Range("A1")
End Sub
The end result would be this:

VBA Excel Line Break in Cell

I've been searching for a solution to this problem for over a week now. I have a sheet with formatted text (colors and styling) with values an undetermined distance down the first column. There are some spaces in between but I believe I've handled that situation correctly by using IsEmpty. I want to copy each of these values from each cell all to one cell at the top of the second column. I've been successful in being able to copy the text from each of these cells into a specified concatenated cell with line breaks, however I've been unsuccessful at keeping the formatting. Any help anyone can provide on how to copy the formatting along with this text would be greatly appreciated. Thank you!
'set variable to find the last row of the sheet
Dim LastRow As Integer
'find the last row of the active sheet
LastRow = ActiveSheet.UsedRange.Rows.Count
'loop through each of the rows
For C = 1 To LastRow
'determine if a cell has a value in it - if so complete below commands
If (IsEmpty(Cells(C, 1).Value) = False) Then
'leave the contents of the first cell in the second column, insert a linebreak and copy the values from the current cell in the first column
Cells(1, 2).Value = Cells(1, 2).Value & Chr(10) & Cells(C, 1).Value
End If
Next C
You can make use of Range.Copy and Range.PasteSpecial properties that is easy to use and solved your problem of formatting cell .