Excel VBA - selecting range to last completely blank row - vba

I have some VBA code that needs to select a range from A84 to X. I'm using this code to select that range to the last row in the data.
Dim Lastrow As Integer
Lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
Range("A84:X" & Lastrow).Select
This stops at the first row with a blank cell in the A column. I need it to check columns A through Z, not just A. For example, if there is a value in column A on rows 84 to 94, but for row 95, there's only data in column F or R, it won't include row 95. How can this look at columns A:Z to determine whether or not the row is blank?

simply set Lastrow to
Lastrow = Range("A:Z").Find("*", , , , xlByRows, xlPrevious).Row

I'm all but certain there is a better way, but one such way is to loop through you columns and find the last row of each and then determine which one of those is the greatest.
maxRow = 0
for i=1 to 24 'A through X
if maxRow < ActiveSheet.Cells(Rows.Count, i).End(xlUp).Row then
maxRow = ActiveSheet.Cells(Rows.Count, i).End(xlUp).Row
end if
next i
Then maxRow is what you want lastrow to be.

You could iterate through all of the columns and compare the last row of each column. You could then change the lastRow variable whenever you find a column with more rows like so:
Dim i As Integer
Dim lastRow As Integer
lastRow = 1
For i = 1 To 26
Dim lst As Integer
lst = Cells(Rows.Count, i).End(xlUp).Row
If lst > lastRow Then
lastRow = lst
End If
Next
Range("A84:X" & lastRow).Select

You can make use of the usedrange function, which returns the complete range of used cells on your sheet:, as follows:
Worksheets("worksheetName").UsedRange.lastRow
This would give you the last used row, not just the last row with data in the first column

Related

Populating cells until last row with a formula VBA

ExcelSheetImage
I want to populate the cells until the last row and the last column. The number of columns and rows vary for each excel sheet I am going through.
So far I have the code below for populating all the rows in column C but it doesn't compile
Sub populate()
Dim lastrow, lastcol As Long
lastrow = Sheet1.Cells(Rows.Count, 2).End(xlUp).Row + 1 'finds last row in B
Range(lastrow, 3).Formula = "=sum(A2:B2)" 'populates cells in C with formula
until last row
End Sub
Range expects two cells a start and an end or a string. Cells take a row and column
Sub populate()
Dim lastrow, lastcol As Long
lastrow = Sheet1.Cells(Sheet1.Rows.Count, 2).End(xlUp).Row + 1 'finds last row in B
Sheet1.Range("C2",Sheet1.Cells(lastrow, 3).Formula = "=sum(A2:B2)" 'populates cells in C with formula
End Sub

How to modify VBA macro to run only on columns of selected cell?

I am using the macro below to keep cells only in a specified interval and remove the rest (i.e. keep the 1st, 5th, 10th, etc. point in a given column)
Dim i As Long
Dim lastRow As Long
lastRow = Application.ActiveSheet.UsedRange.Rows.Count
For i = 2 To lastRow Step 5
Range(Rows(i), Rows(i+8)).ClearContents
Next i
Currently, the macro deletes entire rows on the entire worksheet. I would like to modify the macro I can select the cell at the top of a single column I want to modify and run the macro only on that column.
For example, I have data in, say, A1:B350 and C1:E95 (both on the same sheet). I want to be able to run the macro and keep only a specified interval of cells in columns A-B without disturbing columns C-E. Likewise, I would like to run the same macro in column C without disturbing data in Column A. At this point, I am not sure how to modify this macro to meet this task. I'd greatly appreciate any help and guidance.
The following code will only affect the column you select, but I altered the step from 8 to 12 since otherwise all values were being cleared. Also, the usedRange function may not make sense since now only one column is the focus. Hopefully this code will get you started and you can adjust as needed.
Sub delColumnData()
Dim r As Range, col As Long, LastRow As Long, i As Long
Set r = Application.InputBox("select column", , , Type:=8)
col = r.Column
Set r = Cells(1, col)
LastRow = r.End(xlDown).row
For i = 2 To LastRow Step 12
Range(Cells(i, col), Cells(i + 8, col)).ClearContents
Next i
End Sub
To handle multiple columns:
Sub delColumnsData()
Dim r As Range, col As Long, LastRow As Long, i As Long, j As Long
Set r = Application.InputBox("select column(s)", , , Type:=8)
For j = 1 To r.columns.Count
col = r(j).Column
LastRow = r(j).End(xlDown).row
For i = 2 To LastRow Step 12
Range(cells(i, col), cells(i + 8, col)).ClearContents
Next i
Next j
End Sub
Another option
Option Explicit
Public Sub ClearColumnValues()
Dim i As Long, selectedCol As Long
selectedCol = Selection.Column 'in this case the Selection object can be convenient
With Application.ActiveSheet
For i = 1 To .UsedRange.Rows.Count Step 6
.Range(.Cells(i + 1, selectedCol), .Cells(i + 5, selectedCol)).ClearContents
Next
End With
End Sub

First used row in my selected column

I want to clear all cells in my worksheet from first used to last used row in my selected column, but first I must know the first used row in my selected column. How can I find the first row in "X" column? (X may = {A, B, C, ...})
Try
firstUsedRow = Worksheets("Sheet1").Cells(1, 1).End(xlDown).Row
Where the second argument in Cells(1, 1) is the column number (e.g., A=1, B=2, etc.). Sheet1 is the worksheet name of the worksheet in question.
It is possible, though unlikely in your case, that the first row is row 1. In this case, the above code will actually select your last row of the used range. As a safety measure for this case, identify the last row and make sure your first row is either 1 or the row generated by the above code. So
finalRow = Worksheets("Sheet1").Cells(Worksheets("Sheet1").UsedRange.Rows.Count, 1).End(xlUp).Row
if finalRow = firstUsedRow then
firstUsedRow = 1
End If
All together
firstUsedRow = Worksheets("Sheet1").Cells(1, 1).End(xlDown).Row
finalRow = Worksheets("Sheet1").Cells(Worksheets("Sheet1").UsedRange.Rows.Count, 1).End(xlUp).Row
if finalRow = firstUsedRow then
firstUsedRow = 1
End If
Kindly see the code below. It will skip over all the blank rows in column A represented by second argument of Cells as 1. Then assign the row positions for variables firstRow and lastRow. Last clear the values from that range.
Sub ClearCells()
Dim i As Integer
Dim firstRow As Integer
Dim lastRow As Integer
i = 1
Do While Cells(i, 1) = ""
i = i + 1
Loop
firstRow = i
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
Range(Cells(firstRow, 1), Cells(lastRow, 1)).ClearContents
End Sub
See below with no loop.
Sub ClearCells()
Dim firstRow As Integer
Dim lastRow As Integer
firstRow = Cells(1, 1).End(xlDown).Row
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
Range(Cells(firstRow, 1), Cells(lastRow, 1)).ClearContents
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

Infinite loop while gathering datasets from several worksheets

This is my first time to code in VBA.
I have several worksheets in a file and they are in order by dates.
So what I am trying to do is to collect data sets in a worksheet if they have the same period of time.
date1 value1
date2 value2
date3 value3
Since they are in order I just compare the first date values and if they are different it moves on to the next worksheet. If they are the same then copy the value and do the same process until it reaches the last worksheet.
However it copies one worksheet fine but after that Excel freezes.
I would be appreciated if you find any errors or give me other suggestions to do it.
Following is my code:
Sub matchingStock()
Dim sh1 As Worksheet, sh2 As Worksheet
' create short references to sheets
' inside the Sheets() use either the tab number or name
Set sh1 = Sheets("combined")
Dim col As Long
'since first column is for Tbill it stock price should place from the third column
col = 3
Dim k As Long
'go through all the stock worksheets
For k = Sheets("WLT").Index To Sheets("ARNA").Index
Set sh2 = Sheets(k)
' Create iterators
Dim i As Long, j As Long
' Create last rows values for the columns you will be comparing
Dim lr1 As Long, lr2 As Long
' create a reference variable to the next available row
Dim nxtRow As Long
' Create ranges to easily reference data
Dim rng1 As Range, rng2 As Range
' Assign values to variables
lr1 = sh1.Range("A" & Rows.Count).End(xlUp).Row
lr2 = sh2.Range("A" & Rows.Count).End(xlUp).Row
If sh1.Range("A3").Value = sh2.Range("A3").Value Then
Application.ScreenUpdating = False
' Loop through column A on sheet1
For i = 2 To lr1
Set rng1 = sh1.Range("A" & i)
' Loop through column A on sheet1
For j = 2 To lr2
Set rng2 = sh2.Range("A" & j)
' compare the words in column a on sheet1 with the words in column on sheet2
'Dim date1 As Date
'Dim date2 As Date
'date1 = TimeValue(sh1.Range("A3"))
'date2 = TimeValue(sh2.Range("A3"))
sh1.Cells(1, col).Value = sh2.Range("A1").Value
' find next empty row
nxtRow = sh1.Cells(Rows.Count, col).End(xlUp).Row + 1
' copy the word in column A on sheet2 to the next available row in sheet1
' copy the value ( offset(0,1) Column B ) to the next available row in sheet1
sh1.Cells(nxtRow, col).Value = rng2.Offset(0, 6).Value
'when the date is different skip to the next worksheet
Set rng2 = Nothing
Next j
Set rng1 = Nothing
Next i
'sh3.Rows("1:1").Delete
Else
GoTo Skip
End If
Skip:
col = col + 1
Next k
End Sub
I cannot identify a specific error so this is a list of suggestions that may help you identify the error and may help improve your code.
Suggestion 1
Do you think the Else block of If-Then-Else-End-If is compulsory?
If sh1.Range("A3").Value = sh2.Range("A3").Value Then
:
Else
GoTo Skip
End If
Skip:
is the same as:
If sh1.Range("A3").Value = sh2.Range("A3").Value Then
:
End If
Suggestion 2
I do not like:
For k = Sheets("WLT").Index To Sheets("ARNA").Index
The value of property Index for a worksheet may not what you think it is. This may not give you the set or sequence of worksheets you expect. Do you want every worksheet except "Combined"? The following should be more reliable:
For k = 1 To Worksheets.Count
If Worksheets(k).Name <> sh1.Name Then
:
End If
Next
Suggestion 3
You use:
.Range("A" & Rows.Count)
.Range("A3")
.Cells(1, col).Value
.Cells(Rows.Count, col)
rng2.Offset(0, 6)
All these methods of identifying a cell or a range have their purposes. However, I find it confusing to use more than one at a time. I find .Cells(row, column) and .Range(.Cells(row1, column1), .Cells(row2, column2)) to be the most versatile and use them unless there is a powerful reason to use one of the other methods.
Suggestion 4
I cannot decypher what this code is attempting to achieve.
You say: "I have several worksheets in a file and they are in order by dates. So what I am trying to do is to collect data sets in a worksheet if they have the same period of time."
If you have set Worksheet("combined").Range("A3").Value to a particular date and you want to collect data from all those sheets with the same value in cell A3 then the outer For-Loop and the If give this effect. But if so, if does not matter how the worksheets are ordered. Also you start checking cell values from row 2 which suggests row 3 is a regular data row.
The outer loop is for each worksheet, the next loop is for each row in "combined" and the inner loop is for each row in the worksheet selected by the outer loop. The middle loop does not appear to do anything but set rng1 which is not used.
Perhaps you can add an explanation of what you are trying to achieve.
Suggestion 5
Are you trying to add an entire column of values from the source worksheets to "Combined". The macro below:
Identifies the next free row in column A of "Combined"
Identifies the last used row in column A of "Sheet2"
Assumes the first interesting row of "Sheet2" is 2.
Adds the entire used range of column A of "Sheet2" (complete with formatting) to the end of "Combined"'s column A in a single statement.
This may demonstrate a better way of achieving the effect you seek.
Sub Test()
Dim RngSrc As Range
Dim RngDest As Range
Dim RowCombNext As Long
Dim RowSrcFirst As Long
Dim RowSrcLast As Long
With Worksheets("Combined")
RowCombNext = .Cells(Rows.Count, "A").End(xlUp).Row + 1
Set RngDest = .Cells(RowCombNext, "A")
End With
With Worksheets("Sheet2")
RowSrcFirst = 2
RowSrcLast = .Cells(Rows.Count, "A").End(xlUp).Row
Set RngSrc = .Range(.Cells(RowSrcFirst, "A"), .Cells(RowSrcLast, "A"))
End With
RngSrc.Copy Destination:=RngDest
End Sub