Last row in column VBA - excel

I wrote a short VBA code to automate stuff.
A short snippet is as follows:
Sub TEST()
Rows("1:2").Select
Selection.Delete Shift:=xlUp
Range("A1").Select
ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$1:$O$148"), , xlYes).Name = _
"Table2"
End Sub
However, every Excel file differs with regards to the number of rows. Now when I recorded this macro it just takes the range of $A$1:$O$148. How can I adjust this part so that it automatically recognizes the last row and/or range?
I already tried:
.Range("A1").SpecialCells(xlCellTypeLastCell).Row
Instead of:
Range("$A$1:$O$148")
Thanks in advance!

Generally, you can find the last row / column and therefore the complete used range by using:
ActiveWorkbook.Worksheets("NAME").Range("A" & Rows.Count).End(xlUp).row
for the last row and
ActiveWorkbook.Worksheets("NAME").Cells(1, Columns.Count).End(xlToLeft).Column
for the last column.
I would advice against using UsedRange because if you have blanks in between, it will lead to mistakes.

This is the way I do it and I'm guessing this is a duplicate, but you can mimic hitting End-Up from a row well below your used range with
finalRow = Range("A65000").End(xlup).Row
then you can do
ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$1:$O$" & finalRow & ""), , xlYes).Name = _
"Table2"

You can use the UsedRange property of your worksheet-object.
You can get the indexes of your last used row and column using
ActiveSheet.UsedRange.Columns.Count
ActiveSheet.UsedRange.Rows.Count
So you would basically use this like
With m_Sheet
' Use this range
.Range(.UsedRange.Rows.Count, .UsedRange.Columns.Count)
End With

I used the shortcut Ctrl+Arrow Down, which resulted in following VBA (after recording the macro):
Selection.End(xlDown).Select

This will do the trick:
Dim rSource As Range
With Worksheets("Sheet1")
Set rSource = .Range("A1", .Columns("A:O").Find(What:="*", After:=.Range("A1"), SearchDirection:=xlPrevious))
End With

This would help if you don't know much of the vba library or syntax like me.
Dim lastline as long
Dim lastColumnline as long
dim usedcells as long
dim i as long
dim YOURCOLUMN as long
dim count as long
Set ws = Worksheet("blablabla")
lastline = ws.UsedRange.SpecialCells(xlCellTypeLastCell).Row
usedcells = Application.WorksheetFunction.CountA(ws.Columns(YOURCOLUMN))
for i = 1 to lastline
if ws.cells(i,YOURCOLUMN) <> vbnullstring then
count = count + 1
if count = usedcells then
lastColumnline = i
'i is the lastColumnline
end if
end if
next i

This is how I locate last row:
Function lastRow(Optional strSheet As String, Optional column_to_check As Long = 1) As Long
Dim shSheet As Worksheet
If strSheet = vbNullString Then
Set shSheet = ActiveSheet
Else
Set shSheet = Worksheets(strSheet)
End If
lastRow = shSheet.Cells(shSheet.Rows.Count, column_to_check).End(xlUp).Row
End Function
The column is optional, if no value is given, it is column A.
My GitHub repository with LastThings is here.

Related

Paste data in a specific row, depending on the number in column 43 (AQ)

My Problem seems simple but i'm just not able to solve it alone. My VBA Code copies Data, based on a Filter and past it to another Workbook, starting in Row 1. What i want to change now is, that the Code checks the Number in Column 43 (AQ) from every Row he copies and paste the Row into the Row that matches that Number. For Example: If the Number 7 stands in AQ than the Row should be pasted in row 7. If the Number 3 stands there, it should be pasted into Row 3. In between some Numbers are not included so it can be, that some Rows in between are staying empty.
My intially Code to Copy/Paste data, that worked, was this one.
Sub SG7Stundenplan()
SG7Stundenplan
Sheets("Gruppenplanung").Select
Columns.EntireColumn.Hidden = False
Range("A2").Select
If ActiveSheet.FilterMode Then ActiveSheet.ShowAllData
ActiveSheet.Range("A2").AutoFilter Field:=19, Criteria1:="SG 7", Operator:=xlAnd
Rows("3:100").Select
Selection.Copy
Workbooks.Open "R:\BINplus\Langenthal\Stammgruppen\Stammgruppe 7\Stammgruppe 7_Unterrichtspläne Test.xlsm"
Worksheets("Stammdaten").Range("A1").PasteSpecial Paste:=xlPasteValues
Workbooks("Stammgruppe 7_Unterrichtspläne Test.xlsm").Close SaveChanges:=True
End Sub
I allready tried to create something new but i failed till now. Im pretty sure you need to copy the Rows singulary to put that trick off.
Sub SG7Stundenplan()
Dim Zelle As Range
Workbooks.Open "R:\BINplus\Langenthal\Stammgruppen\Stammgruppe 7\Stammgruppe 7_Unterrichtspläne Test.xlsm"
For Each Zelle In ThisWorkbook.Sheets("Gruppenplanung").UsedRange.Columns(19)
If Zelle.Text = "SG 7" Then
Zelle.EntireRow.Copy
Workbooks("Stammgruppe 7_Unterrichtspläne Test.xlsm").Worksheets("Stammdaten").Cells(Zelle.Offset(43 - Zelle.Column).Value, 1).PasteSpecial xlPasteValues
End If
Next
Workbooks("Stammgruppe 8_Unterrichtspläne Test.xlsm").Close True
End Sub
Thanks a lot for checking this Post and think about it. Your a great Community that allready helped me a lot.
Sincerely,
David from Switzerland
here is my best attempt at your problem.
My Input Sheet:
My Code:
Sub copyData()
Dim src As Worksheet: Set src = ThisWorkbook.Worksheets("Sheet1")
Dim wb As Workbook: Set wb = Workbooks.Open("c:\Desktop\Destination.xlsx")
Dim dest As Worksheet: Set dest = wb.Sheets("Sheet1")
Dim lastRow As Integer: lastRow = src.Cells(src.Rows.Count, 1).End(xlUp).Row
Dim lastCol As Integer: lastCol = src.Cells(1, src.Columns.Count).End(xlToLeft).Column
Dim r As Integer, sendRow As Integer
For r = 2 To lastRow
sendRow = src.Cells(r, 1).Value
src.Range(src.Cells(r, 1), src.Cells(r, lastCol)).Copy Destination:=dest.Range(dest.Cells(sendRow, 1), dest.Cells(sendRow, 1))
Next r
End Sub
My Output:
Good Luck!

can someone help me make this formula work on an entire column?

im hoping that someone can help me to take a macro down an entire column.here is what i am trying to do.
the following table is in a worksheet called barcode. it is my master list. column E:E, is a helper column that has part numbers with countif numbers attach like so=:1,:2,:3, etc. i did this because i have multiple orders for part numbers that are due on different dates in the order report. in column c, there is a number of how many of a part has been ran. in column d, the number of parts that have been scrapped and would have to be ran again. i have highlighted a row to use as an example. in this case. part number ms-100 has a total of 1 part ran and zero scrapped.
the next sheet is my order report sheet. it displays what a customer has ordered of what part. the calculation that i want to have is: if ms-100:1 on the order report matches what is on the master list, then take the qty from the order report and subtract how many were ran, and add how many were scrapped. so for this case. if ms-100:1 =ms-100:1 then cell f8 =12-1+0.
my current code will do that, but it will only do the cells that i point them to and not the entire column. to make it easier to see if this code works or not, instead of changing the values of column f on the order report, i moved it to column l. the goal is to have the value change in f, but for now i was putting the value in l. as you can see, in L7, it says no order. i hope this clarifies what i am trying to accomplish. thank you very much. here is the code that i have so far. i was attempting to use for each cell but it doesnt seem to be working.
Sub FIND_MATCHES()
Dim sh1 As Worksheet
Dim sh4 As Worksheet
Set sh1 = ActiveWorkbook.Sheets("BARCODE")
Set sh4 = ActiveWorkbook.Sheets("ORDER REPORT")
Dim CELL As Range
Dim LASTROW As Long
Dim R As Long
Dim c As Range
Set c = sh4.Range("L:L")
LASTROW = sh4.CELLS(Rows.COUNT, 12).End(xlDown).Row
'LASTROW = Range("F7:F" & Rows.COUNT).End(xlUp).Row
Dim COMPID As Range
Set COMPID = sh1.Range("E:E").Find(What:=sh4.Range("N7").Value, LookIn:=xlValues, LOOKAT:=xlWhole)
'sh4.Range("L7:L" & LASTROW).Activate
'sh4.Range("L7:L" & LASTROW).Select
For Each CELL In c
If COMPID Is Nothing Then
sh4.Range("L7").Value = "NO ORDER"
Else
'TEST CELL'sh4.Range("L7").Value = COMPID.Offset(, -2).Value
sh4.Range("L7").Value = sh4.Range("F7").Value - COMPID.Offset(0, -2).Value + COMPID.Offset(0, -1).Value
'Range("L7:L" & LASTROW).Select
' Range("L8").Select
Exit For
End If
Next CELL
End Sub
I was able to find the solution myself. the below code is what i used. I thought i would share it just in case someone else had the same issue.
Sub FIND_MATCHES()
Dim barcode As Worksheet
Dim order As Worksheet
Set barcode = ActiveWorkbook.Sheets("BARCODE")
Set order = ActiveWorkbook.Sheets("ORDER REPORT")
Dim LASTROW As Long
Dim c As Long
Dim X As Integer
X = 1
Dim finalrow As String
finalrow = order.cells(Rows.COUNT, 12).End(xlUp).Row
Dim location As Range
Set location = barcode.cells.Item(X, "E")
Dim HELPER As String
Dim NUMROWS As String
NUMROWS = order.cells(Rows.COUNT, 14).End(xlUp).Row
HELPER = barcode.cells.Item(X, "E").Value
LASTROW = order.cells(Rows.COUNT, 14).End(xlUp).Row
Dim ENDROW As String
ENDROW = order.cells(Rows.COUNT, 4).End(xlUp).Row
For X = 1 To ENDROW
For c = 7 To NUMROWS
If order.cells(c, 14).Value = barcode.cells.Item(X, "E").Value Then
order.cells(c, 12).Value = order.cells(c, 6).Value - barcode.cells.Item(X, "E").OFFSET(0, -2).Value + barcode.cells.Item(X, "E").OFFSET(0, -1).Value
Else
ActiveCell.OFFSET(1, 0).Select
End If
Next c
Next X
order.Range("A2").Select
End Sub

find first completely empty row on a sheet

need a function that returns the first completely empty row (no values, no formulas, no blanks) from a sheet with sparely populated cells. No one single column is required to be filled.
I tried this, but i can even get it to compile:
Public Donations As Worksheet
Set Donations = Sheets("Sheet2")
Function getEmptyRow() As Long
Dim lastCol As Long, lastRow As Long, maxRow As Long
Dim col As Long
Dim r As Variant
lastCol = Donations.Cells(1, Columns.Count).End(xlToLeft).Column
For col = 1 To lastCol Step 1
lastRow = Donations.Cells(Rows.Count, col).End(xlUp).row
maxRow = Application.WorksheetFunction.max(maxRow, lastRow)
Next col
getEmptyRow = maxRow + 1
End Function
Using EntireRow (which is so useful let me tell you) and counting row by row starting in A1 is one very basic way of doing this.
This will tell you in the immediate window:
Sub findemptyrow() '''Psuedo Code
Application.ScreenUpdating = False 'turns off annoying blinky
Range("a1").Activate 'start at beginning
While a <> 1 'keep going
If Application.CountA(ActiveCell.EntireRow) = 0 Then 'is it blank?
Debug.Print "Row " & (ActiveCell.Row) & " is blank." 'it is
a = 1 'stop going
End If
ActiveCell.Offset(1).Activate 'next cell
Wend 'do it all over again
Application.ScreenUpdating = True 'back to normal settings
End Sub
Making ScreenUpdating False will make this faster, even with 10k's of rows.
The Range.Find method is likely the most expedient method. Look for a wildcard (What:=Chr(42)), start in A1 (After:=.Cells(1, 1), search backwards (SearchDirection:=xlPrevious), search row-by-row (SearchOrder:=xlByRows).Row), look at the formulas (LookIn:=xlFormulas) since that will find the first value or formula; looking at xlValues may not be correct if a formula is returning an empty string ("").
Option Explicit
Public Donations As Worksheet
Sub test()
Set Donations = Worksheets("Sheet2")
Debug.Print getNextEmptyRow(Donations)
End Sub
Function getNextEmptyRow(ws As Worksheet)
With ws.Cells
getNextEmptyRow = .Find(What:=Chr(42), After:=.Cells(1, 1), LookIn:=xlFormulas, _
SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row + 1
End With
End Function
You cannot set Donations in the declarations area of a module code sheet. Declare the public variable in the declarations area (top) of the code sheet but Set the variable in a sub or function.
Don't forget to add 1 to the row returned if you want the 'next empty row'.
Just another alternative using the SpecialCells method of a `Range:
Option Explicit
Sub Test()
Debug.Print "Last row on Sheet1 is: " & FirstCompletelyEmptyRow(Sheet1)
End Sub
Function FirstCompletelyEmptyRow(ByRef wsTarget As Worksheet) As Long
FirstCompletelyEmptyRow = wsTarget.Range("A1").SpecialCells(xlCellTypeLastCell).Row + 1
End Function

reference last column of worksheet

All of the below methods have failed to reference the last column. What is a viable method?
For example 'Columns("1:" & llc.Address & "").Select through 'Columns("E:" & llc & "").Selectare trying to select sayColumns("E:N")`. But the last column is dynamic. In one instance it's column N, and in another application of the macro it's column AP.
Sub RestorePivtTable()
Set ws = ThisWorkbook.Sheets("sheet1")
llc = ws.Cells(2, ws.Columns.count).End(xlToLeft).Column
'Columns("1:" & llc.Address & "").Select
'Columns(1, llc).Select
'Range(Columns(1), Columns(llc)).Select
'Columns("E:" & Cells(3, llc).Address & "").Select
'Range("1:" & Cells(3, lc).Address & "").Select
'Range(Cells(1, 1).Address, Cells(3, llc).Address).Select
'Columns("E:" & llc & "").Select
Selection.ClearFormats
End Sub
If you are using your above method you will need to find the correct row to use. ie: you will need to know the row in which the data appears in the right-most column. If you want the last column out of anything, try:
ws.usedrange.columns
This just gives the number of columns in the used range of a sheet, which is defined as A1:[The bottom right cell which contains either values or formatting].
Note that this will not work if, say, you have formatting in E10, but you want to get column D, because D is the last column which has a value [ie: you want to exclude consideration of formatted cells].
I generally use this method, although you have to put checks in in case the sheet is empty (you can't return column 0).
Sub FindLastColumn()
Dim wrkSht As Worksheet
Set wrkSht = ThisWorkbook.Worksheets("Sheet1")
MsgBox wrkSht.Cells.Find(What:="*", After:=wrkSht.Cells(1, 1), SearchDirection:=xlPrevious).Column
End Sub
Basic example of how to find the last column in your sheet - I've included an If block in case the sheet is empty, but then I don't know why you would run this code on an empty sheet anyway...
Sub SO()
Dim lastCol As Integer
Dim lastCell As Excel.Range
'// Assuming the variable 'ws' has already been dimensioned and initialised
On Error Resume Next
Set lastCell = ws.Cells.Find(What:="*", After:=ws.Range("A1"), SearchDirection:=xlPrevious)
On Error GoTo 0
If lastCell Is Nothing Then
lastCol = 1
Else
lastCol = lastCell.Column
End If
MsgBox lastCol
End Sub
UsedRange can be unreliable in this instance, because it can still contain cells that were previously used but are now blank - and I'm guessing you're not interested in these cells. Using the Cells.Find() method means that you don't have to know which row will coincide with the last column (which is needed for Columns.Count.End(xlToLeft) method) so this is a bonus too when working with irregular data sets.
Trying to "read between the lines" of your code, I suspect that this is what you are after:
Public Sub RestorePivtTable()
Sheet1.Cells(2, Sheet1.Columns.Count).End(xlToLeft).EntireColumn.ClearFormats
End Sub
This will work as long as there are data in row 2.
Thanks everyone for your help. The below function and macro solved the issue of converting a column number reference into a letter reference:
Function GetColumnLetter(colNum As Long) As String
Dim vArr
vArr = Split(Cells(1, colNum).Address(True, False), "$")
GetColumnLetter = vArr(0)
End Function
Sub RestorePivtTable2()
Dim lc As Long
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("PivtTable")
lc = ws.Cells(5, ws.Columns.count).End(xlToLeft).Column
myCol = GetColumnLetter(lc)
Columns("E:" & myCol & "").Select
Selection.ClearFormats
End Sub

vba iterate over columns with formulas and filldown

I have a datasheet that is imported regularly and the length changes.
So, I want to write some VBA code that deletes any extra rows and autofills any formulas to the last row.
I have the first part done. This code finds the last row, and deletes anything below it.
Sub CleanData()
Dim lastrow As Long
Sheets("Open Operations").Select
Range(Cells(Rows.Count, 1).End(xlUp).Offset(1), _
Cells(Rows.Count, 1)).EntireRow.Delete
lastrow = ActiveSheet.UsedRange.Rows.Count
End Sub
The part I'm stuck on is that I'm not sure how to autofill any columns that need it. These columns could be changing, so I want my code to be able to handle this. So, I want to iterate over all of the cells in the first row, from the very first column to the last column in use. Then, if that cell is a formula, I want to fill the formula down to the lastrow, as defined in the first code block.
Here's what I have so far:
Dim lastcolumn As Long
lastcolumn = ws.Cells(1, Columns.Count).End(xlToLeft).Column
For Each c In ActiveSheet.Range("A1:A" & lastcolumn).Cells
If c.HasFormula = True Then
But I'm pretty new to VBA, and I'm not sure how to make the column fill down to the previously defined Last Row.
EDIT: To clarify -- I want to iterate over every first cell in each column until the last column. Then, if that cell contains a formula, I want to autofill/filldown that whole column to the lastrow defined in the first code block.
Thanks.
I've managed to create code that accomplishes the task mentioned above:
Here is the code for anyone interested:
Sub CleanData()
' Clean the data
Application.Calculation = xlManual
Call CleanSheet("Order Headers")
Call CleanSheet("Open Operations")
Call CleanSheet("Confirmations (SAP)")
Call CleanSheet("VA05")
Call CleanSheet("ZOOP")
Call CleanSheet("PremExped")
Application.Calculation = xlCalculationAutomatic
End Sub
Sub CleanSheet(SheetName As String)
' Cleans the Sheet specified by SheetName
' Variable Declaration
Dim NumColumns As Long
Dim NumRows As Long
Dim ColumnCounter As Long
' Find the number of rows and columns in SheetName
NumRows = Sheets(SheetName).Cells(Rows.Count, 1).End(xlUp).Row
NumColumns = Sheets(SheetName.Cells(1, Columns.Count).End(xlToLeft).Column
' Define the ranges for pulling down the formulas
Set rng1 = Worksheets(SheetName).Range("A2:A" & NumRows)
Set rng2 = Worksheets(SheetName).Range("A2")
' Delete extraneous rows of data
Sheets(SheetName).Select
Range(Cells(Rows.Count, 1).End(xlUp).Offset(1), _
Cells(Rows.Count, 1)).EntireRow.Delete
' Ensure all formulas are dragged down appropriately
For ColumnCounter = 0 To NumColumns
If rng2.Offset(0, ColumnCounter).HasFormula = True Then
rng1.Offset(0, ColumnCounter).FillDown
End If
Next ColumnCounter
End Sub
("A1:A" & lColumn) seems to confuse rows and columns.
I think you want:
LastRow = ActiveSheet.UsedRange.Row + ActiveSheet.UsedRange.Rows.Count - 1
or
LastRow = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
EDIT: Maybe just the following:
For Each c In ActiveSheet.UsedRange

Resources