Finding the Last Row and using it in a formula - vba

I am dealing with a sheet of data that has multiple rows ans columns. Each time the macro runs, the number of rows can be different, so I am trying to find the last row for a column.
With the last row, I am trying to do a calculation. For example: if the row I get is 1200, I can do A1200/A2-1. MY code should explicitly paste the formula in an output worksheet and currently (currently I have to put the last row myself).
Question: How can I get the last row and put it in a formula? Should I assign it to a variable and then use the variable in the formula?
Lines of code I am using:
Sub Output()
Dim LastRowA As Long
LastRowA = Worksheets("Sheet2").Cells(Rows.Count, "A").End(xlUp).Row
'this is my current method, it works using specific cells.
'I would like to change the D1662, for example, for a floating reference that gets the last row
Worksheets("Sheet2").Range("C2:C2").Formula = "='TIME SERIES'!D1662/'TIME SERIES'!D2-1"
End Sub

Like so. Just remove the variable from the quotes.
Sub Output()
Dim LastRowA As Long
LastRowA = Worksheets("Sheet2").Cells(Rows.Count, "A").End(xlUp).Row
'this is my current method, it works using specific cells.
'I would like to change the D1662, for example, for a floating reference that gets the last row
Worksheets("Sheet2").Range("C2:C2").Formula = "='TIME SERIES'!D" & LastRowA & "/'TIME SERIES'!D2-1"
End Sub

How about a user defined function? This way you can add it to your equation in excel with =LastRow(ColumnNumber). You can leave this in the vba editor and in excel set you cell value to "=LastRowValue("SheetName",1)/A2-1" where 1 would be column A.
Function LastRowValue(WorksheetName As String, Col As Long) As Long
'=======================================================================
'This can be typed into an excel cell as a normal function
'"=LastRow("SheetName",ColumnNumber)" The Column Number is indexed
'starting with A=1 so C=3 and AA=27. Enter the WorksheetName in
'quotes "WorksheetName".
'========================================================================
Dim LR As Long
'LR will find the last row in column number "col" in WorksheetName.
LR = ThisWorkbook.Sheets(WorksheetName).Cells(Rows.Count, Col).End(xlUp).Row
'LastRowValue will be the output of this function and will be the value of
'the last row in WorksheetName.
LastRowValue = Cells(LR, Col).Value
End Function

Related

Excel VBA Code for small scroll while there is a value on the right

I have a Macro that takes data out of 2 reports.
in the second report I have dates that I copy. I need to take a date and subtract from it 14 days
I go to first blank cell in column D, then I want to calculate the formula in column C and scroll down without type how many cells (because it is a macro to a daily basis and the amount of data will change). I want to do this until the end of the data I copied.
In the end I want to copy it as values to column B.
Here is what I have in my code(part of all macro):
'first we go to the buttom of the column
'for NOW - change manually the top of the range you paste to
'Now, paste to OP_wb workbook:
OP_wb.Sheets("Optic Main").Range("D1").End(xlDown).Offset(1, 0).PasteSpecial
Paste:=xlPasteValues
' Calculate Due Date to MFG tools
' it means date we copied from MFG daily minus 14 days
_wb.Sheets("Optic Main").Activate
Range("C1").End(xlDown).Offset(1, 0).Activate
ActiveCell.FormulaR1C1 = "=RC[1]-14"enter code here
You need to loop from the first row to the last row. In general, there are plenty of good ways to define the last row of a given column. Once you have done it, replace the value of lngEndRow and run the following code:
Option Explicit
Public Sub TestMe()
Dim lngStartRow As Long: lngStartRow = 1
Dim lngEndRow As Long: lngEndRow = 100
Dim rngMyRange As Range
Dim rngMyCell As Range
With ActiveSheet
Set rngMyRange = .Range(.Cells(lngStartRow, 5), .Cells(lngEndRow, 5))
End With
For Each rngMyCell In rngMyRange
rngMyCell.FormulaR1C1 = "=RC[1]-14"
Next rngMyCell
End Sub
Then change the ActiveSheet with the correct sheet and the column hardcoded as 5 with the correct one. Run the code above in an empty Excel, to understand what it does. Then change it a bit, until it matches your needs.

VBA search column heading in a sheet and return SUM in another sheet

I would like to get datas from sheet 1 to sheet 2 with reference to the column headings With VBA.
For example:(EXCEL file)
So if I want to find the sum of fun1 person A with criteria 1 the command have to go and find the heading “sum of fun 1” in sheet 1 and choose the datas that are only under criteria 1 and sum it up in sheet 2 cell D5. (By using column heading reference instead of cell reference. The table range is A2 : U80. thanks.
Public Sub Match()
ThisWorkbook.Sheets("Sheet1").Activate
Range("Sheet2!B3") = Application.Sum(Application.Index(Range("A:G"), 0, Application.Match("Crit1" & "Fun1personA", Range("A2:G2"), 0)))
End Sub
I have tried it codes but it failed. i know that i havnt include the Row reference for crit1 , but iam not sure how to apply that to the formula.
Can anyone help me with this ? Thanks in advance
You could do it with a formula.
I'll assume that the table in your example covers the range A1:E10.
First we'll need to find the correct column using a MATCH formula:
=MATCH("Fun2PersonA",$1:$1,0) - this will return 3 as Fun2PersonA is in column C.
Next we need to know how many rows are in the table. Assuming the criteria in column A has no blanks except cell A1 we can use COUNTA:
=COUNTA($A:$A)+1 - this will return 10.
The above two formula will be used a few times within the final result, so will probably be easier to use helper cells to store the results (I'll just call them ColumnRef and LastRowRef for readability rather than actual cell references).
Now to set a reference to the first cell and last cell in column C.
=INDEX($1:$1,,ColumnRef) will reference the header, while =INDEX($1:$1048576,RowRef,ColumnRef) will reference the last cell.
As these can be used as references and not just values =SUM(INDEX($1:$1,,ColumnRef):INDEX($1:$1048576,RowRef,ColumnRef)) will sum everything in that column. It's the same as writing =SUM(C1:C10).
But you want to use SUMIF, so we need to reference the criteria in column A as well.
=INDEX($A:$A,RowRef) will reference the last cell in column A, so $A$1:INDEX($A:$A,RowRef) will reference all values in column A.
Final Formula:
The final step is to stick it all together into your final formula:
=SUMIF($A$1:INDEX($A:$A,RowRef),"Crit1",INDEX($1:$1,,ColumnRef):INDEX($1:$1048576,RowRef,ColumnRef))
This is the same as writing =SUMIF($A$1:$A$10,"Crit1",$C$1:$C$10)
For a VBA solution:
Public Function SumCriteria(FunPerson As String, Criteria As String) As Double
Dim rTable As Range
Dim rCol As Range
Dim rCriteria As Range
Dim LastRow As Long
Dim LastCol As Long
'Update Sheet1 to the sheet name with your table.
With ThisWorkbook.Worksheets("Sheet1")
'You may have to change how to find the last row/column depending
'on any extra data on the sheet.
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
LastCol = .Cells(1, Columns.Count).End(xlToLeft).Column
Set rTable = .Range(.Cells(1, 1), .Cells(LastRow, LastCol))
'EDIT: You could set your table as below if it's a static size.
'Set rTable = .Range("A2:U80")
'The first statement finds the FunPerson heading
Set rCol = rTable.Rows(1).Find(What:=FunPerson, LookIn:=xlValues, LookAt:=xlWhole)
If Not rCol Is Nothing Then
SumCriteria = Application.WorksheetFunction.SumIf(rTable.Columns(1), Criteria, rTable.Columns(rCol.Column))
Else
SumCriteria = CVErr(xlErrValue)
End If
End With
End Function
This method looks at column A and row 1 to get the dimensions of the table and then uses SUMIF to count the figures.
You can use it as a worksheet formula: =SumCriteria("Fun1PersonA","Crit1")
or within VBA:
Public Sub Test()
Dim a As Double
a = SumCriteria("Fun1PersonA", "Crit1")
End Sub

IF THEN VBA MACRO - Update one column if contents of another = 100%

I have a workbook with "Results" being sheet 3, this being the worksheet I want to use.
I have tried a few formulaes to try and add a macro to do the following:
I have column G with percentages. I then have column I where I would like there to be a result saying TRUE/FALSE where the contents of G are equal to 100%. Column G is formatted to percentage with two decimals.
Some considerations: I have my first row being a Hyperlink to another sheet, then my headings, then the first row of "results". I have 457 rows, if there is a measurement of the range, perhaps it could be on A?
I keep getting this error 9 with my range and have got a bit stuck.
Thanks in advance!
Sub PartialHits1()
Dim rng As Range
Dim lastRow As Long
Dim cell As Range
With Sheet3
lastRow = .Range("G" & .Rows.Count).End(xlUp).Row
Set rng = .Range("G1:G" & lastRow)
For Each cell In rng
If cell.Value = 100
Then
cell.Range("I1:I1").Value = 100
End If
Next
End With
End Sub
(I have hacked this a bit, just was trying to get it to set as 100 instead of the TRUE/FALSE Also was playing around near the Sheet 3 part as I got errors.)
RangeVariable.Range can refer only to a cell within RangeVariable, so you can't refer to column I in this way. Try: .Range("I"&cell.row)=100.
Also your criteria is probably wrong, if you have 100% in a cell it's actual value is 1.
And last question: why do you want to do this with VBA, it would be much more simple with worksheet function =IF(G3=1,100,"")

Macro for copying a specific Row of formulas into newly created rows

I recently posted a question, and unfortunately did not get very far with any answers. I have re-worked my macro to mirror a similar scenario I found elsewhere. The problem is I am now getting stuck at the very end.
Purpose of the macro:
1. Beneath the selected cell, I need to insert x new rows = entered months -1
In the first inserted row, I need a set of relative formulas that can be found in the Actual Row 2 of the current worksheet (basically copy and paste row 2 into the first row created)
In the subsequent inserted rows, I need a set of relative formulas that can be found in the Actual Row 3 of the current worksheet
As is, the macro does what I want, except I don't know how to paste row 3 in all subsequent rows. I'm assuming I need some conditional statement?
As mentioned in my last post, I am trying to teach myself VBA, so any help would be appreciated!!
Sub InsertMonthsAndFillFormulas(Optional vRows As Long = 0)
Dim x As Long
ActiveCell.EntireRow.Select 'So you do not have to preselect entire row
If vRows = 0 Then
vRows = Application.InputBox(prompt:= _
"Enter the total number of months in the program", Title:="Add Months", _
Default:=1, Type:=1) 'Default for 1 row, type 1 is number
If vRows = False Then Exit Sub
End If
Dim sht As Worksheet, shts() As String, i As Long
ReDim shts(1 To Worksheets.Application.ActiveWorkbook. _
Windows(1).SelectedSheets.Count)
i = 0
For Each sht In _
Application.ActiveWorkbook.Windows(1).SelectedSheets
Sheets(sht.Name).Select
i = i + 1
shts(i) = sht.Name
x = Sheets(sht.Name).UsedRange.Rows.Count 'lastcell fixup
Selection.Resize(rowsize:=2).Rows(2).EntireRow. _
Resize(rowsize:=vRows - 1).Insert Shift:=xlDown
Rows(2).EntireRow.Copy Destination:=Selection.Offset(1).Resize( _
rowsize:=1)
Rows(3).EntireRow.Copy Destination:=Selection.Offset(2).Resize( _
rowsize:=1)
On Error Resume Next
Next sht
Worksheets(shts).Select
End Sub
Ok, based on your comments, the below code should meet your needs. But first, a few things to note.
I've added several comments to help you understand what is happening in the code.
Based on your comment regarding vRows, the code will now terminate if the user keeps the default input box value ("1"). The logic is that if the value is only one, then no rows need to be added. Notice that I subtract 1 from the Inputbox value.
The code assumes you have headers or at least filled cells in row one. I use row one to find the last used column.
If there's any chance that the wrong sheet can be active when this code is executed, uncomment line 16 of my code. (Obviously you'd need to change the code to reflect your sheet's name.
Finally, this code assumes that the upper-left corner of your dataset is in A1.
Tested on Sample Dataset
Sub InsertMonthsAndFillFormulas(Optional vRows As Long = 0)
Dim lastCol As Long
Dim r As Range
'Ask user for number of months.
'If the user keeps the default value (1), exit sub.
If vRows = 0 Then
vRows = Application.InputBox(prompt:= _
"Enter the total number of months in the program", Title:="Add Months", _
Default:=1, Type:=1) - 1
If vRows = 0 Then Exit Sub
End If
'Uncomment this line if you are concerned with which sheet needs to be active.
'ThisWorkbook.Sheets("YourSheet").Select
With ActiveSheet
'Set the range to work with as the cell below the active cell.
Set r = ActiveCell.Offset(1)
'Find the last used column. (Assumes row one contains headers)
'Commented this out to hard-code the last column.
'lastCol = .Rows("1:1").Find("*", searchdirection:=xlPrevious).Column
'Insert the new rows.
r.EntireRow.Resize(vRows).Insert Shift:=xlDown
'r needs to be reset since the new rows pushed it down.
'This time we set r to be the first blank row that will be filled with formulas.
Set r = .Range(.Cells(ActiveCell.Offset(1).Row, 1), _
.Cells(ActiveCell.Offset(1).Row, "H")) '<~~ Replaced lastCol with "H"
'**Add formulas to the new rows.**
'Adds row two formulas to the first blank row.
.Range(.Cells(2, 1), .Cells(2, "H")).Copy r
'Adds row three formulas to the rest of the blank rows.
.Range(.Cells(3, 1), .Cells(3, "H")).Copy r.Offset(1).Resize(vRows - 1)
End With
End Sub
Edit
The variable lastCol is what defines the right most column to copy formulas from. This variable is set using column headers in row 1. I prefer using variables like this to make the code more robust (i.e. you can add a column to your dataset without breaking the macro), however, for this to work you need headers above every used column (or at least cells that contain values).
If you aren't concerned with adding more columns in the furture, you can hard-code the last column into the code (see my revisions).

Excel VBA - Insert Row & Insert Column Macros

I have a "Task Tracker" workbook that uses columns A:J to display and calculate task information (A:E are for user-entered data, F:J contain formulas that use the information in C:E and perform calculations. F:J are hidden cells in the user view.) The remainder of the columns display a heat map of where the tasks fall on a timeline, and whether or not they are running on time, are behind, or are complete.
There are two buttons for users to use: one to insert a new row, and one to insert a new column. The InsertRow() macro inserts a row into the list, then copies the formulas down from the above row. The InsertColumn() macro locates the last used column in the worksheet and copies everything over from the column to the left of it.
Originally, I had a macro for InsertRow using Range that copied from Column F (where the formulas start) to Column XFD. However, once I created the InsertColumn macro I realized that I cannot do InsertRow like that because InsertColumn needs to locate the last data-containing column in the worksheet and add a new one to the right...and if InsertRow gets run first, InsertColumn won't work because the value for lastColumn comes back as the index of column XFD.
What I am looking for help with:
I need to locate the lastColumn value in my InsertRow macro, then use that value as part of the Range when the program executes the Copy/Paste portion of the code. I think that the problem I'm having has to do with the fact that the code I'm using to find the last column returns the index, and the Range function needs the name of the column.
Here is what I have for both macros:
Sub InsertTaskRow()
' InsertTaskRow Macro
'
' This macro inserts a new row below whatever role the user currently has selected, then
' copies the formulas and formatting from above down to the new row
Dim lastColumn As Long
Dim currrentRow As Long
Dim newRow As Long
lastColumn = ActiveSheet.Range("A1").SpecialCells(xlCellTypeLastCell).Column
currentRow = ActiveCell.Row
newRow = currentRow + 1
ActiveCell.Offset(1).EntireRow.Insert Shift:=xlDown
Range("F" & currentRow & ":" & lastColumn & currentRow).Copy Destination:=Range("F" & newRow & ":" & currentRow & newRow)
End Sub
Sub InsertColumn()
' InsertColumn Macro
'
' This macro copies the formulas and formatting from the last data-containing column
' in the worksheet, and pastes it into the next column to the right.
Dim lastColumn As Long
lastColumn = ActiveSheet.Range("A1").SpecialCells(xlCellTypeLastCell).Column
MsgBox lastColumn
Columns(lastColumn).Copy Destination:=Columns(lastColumn + 1)
End Sub
You can try changing your lastColumn occurances to the following:
lastColumn = ActiveSheet.Range("A1").End(xlToRight).Column
This will stretch your range to all used cells. I tried using the clCellTypeLastCell, but it was pulling further than necessary for no apparent reason; even after deleting the entire columns it claimed were applicable. Just an FYI, there is no issue with using indexes or column names when utilizing Range() - even interchangibly, they are both fully qualified.