VBA Excel Clearing - excel

The following code works but runs too slowly on large files, so the code needs to be modified to identify the first year that is earlier than 2019 and then delete that row and the row containing the rest of the years below that, all at one time:
Range("B2").Select
Do Until ActiveCell.Value =""
If ActiveCell.Value < 2019 Then
ActiveCell.EntireRow.Delete
Else
ActiveCell.Offset(1,0).Select
End If
Loop
Code Problem: data sets can have 1000's of rows so checking every cell is very slow. Since the data is always in order, all I need to do is find the first entry <2019 and then select xldown and delete everything, but I don't know how to find that cell and make it the active cell.

as stated in the comments:
Dim firstrow As Variant
firstrow = Application.Match(2018, ActiveSheet.Range("B:B"), -1)
If Not IsError(firstrow) Then
Dim lastrow As Long
lastrow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 2).End(xlUp).Row
ActiveSheet.Rows(firstrow + 1 & ":" & lastrow).Delete
End If

Related

Date stamp code & data overwriting problem

I have written a VBA code which copies data from a pivottable into another worksheet in order to store this data.
The data is monthly and counts the amount of devices, this is needed to create a historical database.
Sub DataTransferv1()
Dim lastrow As Long, erow As Long
'Stamp from when the data set is (in months) Worksheets("Database").Select
Worksheets("Database").Range("A3").Select
If Worksheets("Database").Range("A3").Offset(1, 1) <> "" Then
Worksheets("Database").Range("A3").End(xlDown).Select
ActiveCell.FormulaR1C1 = "=NOW()"
End If
'To check the last filled line on sheet 'Database_Input' lastrow = Sheet12.Cells(Rows.Count, 1).End(xlUp).Row
'Copy Paste section For i = 2 To lastrow
Sheet12.Cells(i, 1).Copy
erow = Sheet14.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
Sheet12.Paste Destination:=Worksheets("Database").Cells(erow, 1)
Sheet12.Cells(i, 2).Copy
Sheet12.Paste Destination:=Worksheets("Database").Cells(erow, 2) Next i
End Sub
The problem with this code, it keeps paste a date stamp in the last used cell (So it overwrites the last row of copied data). How can I fix this as I don't see it anymore. Also, what VBA formula can be used for a static date stamp, in the regular excel its Shift + ; but I cant find the formula for this.
Thank you very much!

Copy rows and paste them as columns in Excel with VBA automatically

I am learning to copy and paste with VBA automatically without overwriting data.
I managed to get a code to copy from rows and paste them as rows.
Now, I want to copy rows (Same way) but paste them as a column each time.
The first line has to start with a date stamp (Each month) and underneath it the amounts. The amounts are being copied from a pivot table which will refresh then each month.
Here is my written code:
Private Sub CommandButton1_Click()
Dim lastrow As Long, ecol As Long
'Stamp from when the data set is (in months)
If Worksheets("Database").Range("A3").Offset(1, 1) <> "" Then
Worksheets("Database").Range("A3").End(xlDown).Select
ActiveCell.Offset(1, 0).FormulaR1C1 = Now
End If
'To check the last filled line on sheet 'Database_Input'
lastrow = Sheet12.Cells(Rows.Count, 2).End(xlUp).Row
'Copy Paste section
For i = 2 To lastrow
Sheet12.Cells(i, 2).Copy
ecol = Sheet14.Cells(3, Columns.Count).End(xlToRight).Offset(0, 1).Column
ecol = Sheet14.Cells(3, Columns.Count).End
Sheet12.Paste Destination:=Sheet14.Cells(3, ecol)
Next i
End Sub
It keeps giving me an error on the following section:
For i = 2 To lastrow
Sheet12.Cells(i, 2).Copy
ecol = Sheet14.Cells(3, Columns.Count).End(xlToRight).Offset(0, 1).Column
ecol = Sheet14.Cells(3, Columns.Count).End
Sheet12.Paste Destination:=Sheet14.Cells(3, ecol)
Next i
Anyone who has an idea how to deal with this? I copied my row --> row code and edited it. Maybe it has to be completely different.
Many thanks!
You are wanting the Column property of the Range, not Columns.
Also, you can transfer the value directly which is slightly more efficient than copying and pasting.
I have made a semi-educated guess as to desired destination range.
For i = 2 To lastrow
ecol = Sheet14.Cells(3, Columns.Count).End(xlToleft).Offset(0, 1).Column 'not columns at the end
Sheet14.Cells(3, ecol).Value = Sheet12.Cells(i, 2).Value
Next i
I didn't even look into your code, if what you want is just transpose version of the data, get your data into an array (range.value will give array) just use a loop to transpose and then assign it to a new range.
If you want them to contain formula use range.formula instead of value. just be sure to care about relative/absolute references.

How to Delete rows according to criteria in cells

I am trying to automate some date filtering for work.
I want to delete rows if they do not fall under this time stamp
2:00am - 10:00am
So if the time is before 2:00am or after 10:00am delete the entire row.
There are multiple rows like this.
I am not sure where to even start because I am very beginner and need an easy code to follow.
Here is what the data would look like
This is similar to this question here where I gave a similar answer. You can give this a try, though this assumes your times are in the 24 hour format and assumes you only want to delete that specific cell and not the entire row.
Sub TimeDelete()
'Declare your variables
Dim timeRng As Range, early As Long, late As Long, lrow As Long
'Finds the last row with a time in it in Column F
lrow = ThisWorkbook.Worksheets("Sheet1").Cells(Rows.Count, 6).End(xlUp).Row
'Define the times you want to compare against
early = "02:00:00"
late = "10:00:00"
'Specifies the range the times are in
Set timeRng = ThisWorkbook.Worksheets("Sheet1").Range(Cells(1,6), Cells(lrow,6))
'Use a For loop to check each value in the range
For Each Cell In timeRng.Cells
If TimeValue(Cell.Value) >= TimeValue(early) And TimeValue(Cell.Value) <= TimeValue(late) Then
Cell.Delete Shift:=xlToLeft 'Deletes cell if it meets the criteria and shifts remaining cells in the row to the left.
End If
Next Cell
End Sub
My VBA is a bit rusty, but this should work
Sub DelStuff()
Dim WB As Workbook
Dim Sheet As Worksheet
Set WB = ActiveWorkbook
Set Sheet = WB.ActiveSheet
For Each r In Sheet.UsedRange.Rows
If Cells(r.Row, "F").Value <= Date & " " & #2:00:00 AM# Or Cells(r.Row, "F").Value >= Date & " " & #10:00:00 AM# Then
r.EntireRow.Delete
End If
Next r
End Sub

How to create a macro that can apply a formula to a dynamic range of cells, preferably using array?

I am completely new to VBA, so this task is a bit difficult for me but I bet it is easy for you guys.
I am trying to create a macro command that can automatically convert a series of dates from text to a date format that excel can recognize. This is a task which I regularly perform, so it would be very time saving to have a macro doing it for me.
Basically, I regularly download a time series of e.g. the historical price of a stock. The length of the time series varies every time.
Next I will need to convert the dates from the downloaded data to a format excel can recognize.
To do so I use the following code:
=DATE(RIGHT(B2,4),MONTH("1 "&MID(B2,4,3)),LEFT(B2,2))
in the cell adjacent to the first row of the date series.
I then auto-fill this formula to the end of the series.
I have created a macro that performs this task for me, using the following code:
Sub FacsetDates()
' FacsetDates Macro
' Turn Factset dates into excel format
'
' Keyboard Shortcut: Ctrl+Shift+D
ActiveCell.FormulaR1C1 = _
"=+DATE(RIGHT(RC[-1],4),MONTH(""1 ""&MID(RC[-1],4,3)),LEFT(RC[-1],2))"
Selection.End(xlToLeft).Select
Dim Lastrow As Long
Lastrow = Cells(Rows.Count - 1, ActiveCell.Column).End(xlUp).Row
Selection.End(xlToRight).Select
Selection.AutoFill Destination:=ActiveCell.Range("A1:A" & Lastrow - 1)
ActiveCell.Range("A1:A" & Lastrow - 1).Select
End Sub
My problem is that this code only works if the date series start from row 2.
If the the series is inserted from row 1 the auto-fill will stop one row short and if the series start from row 3, the auto-fill will fill out one row too much (compared to the length of the data series)
I would like a macro that works no matter which row the data series start.
E.g. I would like the macro to work even if the date series begin at B10.
I imagine that the solution is to set the data series as an array in VBA and then perform a loop that manipulate each string of text, and then finally paste the manipulated data in the adjacent column.
I have started producing the following code:
Sub FSdate()
Dim arrMarks() As Long
Lastrow = Cells(Rows.Count, ActiveCell.Column).End(xlUp).Row
ReDim arrMarks(1 To Lastrow)
Dim i As Long
For i = LBound(arrMarks) To UBound(arrMarks)
arrMarks(i) = ActiveCell
Next i
In which I try to first define the array and its size, and then "copy" the string of text from the active cell (being the first row of the data series), but this code fails.
After having defined the array, I imagined to run a loop that use the DATE function from above to manipulate every single entry in the array. But my current skills in VBA falls short here, and I simply do not know how to proceed.
Can anyone help create such a code?
or even, do you guys have inputs to alternative ways of doing this task?
Probably the initial code can be manipulated to work no matter which row the data series start.
I hope somebody is able and willing to help me!
This is a vary simplified breakdown of #Dave answer, since you want to use the cell you are selecting to start from. First; set your last row by counting the rows in the column to the left from your active cell. Second; set your range from the active cell to the last row variable. Third: write your formula into the range. Note: the lRow - ActiveCell.Row + 1 adjusts your range based on the activecell row number.
Dim lRow As Long
lRow = Cells(Rows.Count, ActiveCell.Offset(, -1).Column).End(xlUp).Row
ActiveCell.Resize(lRow - ActiveCell.Row + 1).FormulaR1C1 = "=+DATE(RIGHT(RC[-1],4),MONTH(""1 ""&MID(RC[-1],4,3)),LEFT(RC[-1],2))"
An easier way to accomplish your task; by overwriting the current text would be to use TextToColumns
ActiveSheet.Columns("F").TextToColumns Destination:=ActiveSheet.Columns("F"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, FieldInfo:=Array(1, 3), TrailingMinusNumbers:=True
Columns("F").NumberFormat = "m/d/yyyy"
If we first look at what's happening:
Sub FacsetDates()
' FacsetDates Macro
' Turn Factset dates into excel format
'
' Keyboard Shortcut: Ctrl+Shift+D
' Enter Formula in the current cell
ActiveCell.FormulaR1C1 = _
"=+DATE(RIGHT(RC[-1],4),MONTH(""1 ""&MID(RC[-1],4,3)),LEFT(RC[-1],2))"
' Move to the leftmost cell in a contiguous range from the current cell
Selection.End(xlToLeft).Select
Dim Lastrow As Long
' Get the row number of the bottom cell in the same column as the now selected cell
Lastrow = Cells(Rows.Count - 1, ActiveCell.Column).End(xlUp).Row
' Move to the rightmost cell in a contiguous range from the now selected cell
Selection.End(xlToRight).Select
' Fill down from the current cell by the same number of cells in the range from A1 to the last row
Selection.AutoFill Destination:=ActiveCell.Range("A1:A" & Lastrow - 1)
ActiveCell.Range("A1:A" & Lastrow - 1).Select
End Sub
Where your issue with the range comes in is that ActiveCell.Range("A1:A" & Lastrow - 1) does not refer to rows 1 to x in the sheet, it refers to rows 1 to x in your range which starts at row 2 or 3 or whatever.
You will also learn very quickly that changing selections in code is time/resource consuming and is susceptible to bugs creeping in eg if selections change during the running of your code.
I would consider hardcoding the column where you are outputting your formula if it is always going to be the same to and to avoid making selections. You can do this and input the formula directly into column C like so:
Sub FacsetDates2()
Dim Lastrow As Long
' Get the row number of the bottom cell in column A
Lastrow = Cells(Rows.Count - 1, 1).End(xlUp).Row
Range("C2:C" & Lastrow).FormulaR1C1 = "=+DATE(RIGHT(RC[-1],4),MONTH(""1 ""&MID(RC[-1],4,3)),LEFT(RC[-1],2))"
End Sub
EDIT -
Using the active cell and going to the end of the range as defined in column A you could use this:
Sub FacsetDates2()
Dim Lastrow As Long
Dim c As Range
Dim currentRow As Long
Dim currentColumn As String
' Store a reference to the active cell
Set c = ActiveCell
' Get the row number and column name of the active cell
currentRow = c.Row
currentColumn = Replace(c.Address, currentRow, "")
' Get the row number of the bottom cell in column A
Lastrow = Cells(Rows.Count - 1, 1).End(xlUp).Row
Range(c.Address & ":" & currentColumn & Lastrow).FormulaR1C1 = "=+DATE(RIGHT(RC[-1],4),MONTH(""1 ""&MID(RC[-1],4,3)),LEFT(RC[-1],2))"
End Sub

Excel macro to cut a specific row of cells from one worksheet to another

I have a worksheet titled CASES-PENDING, with many rows of data. On a daily basis I change the status of a particular row's beginning cell to "done" (changed from "pending"). Instead of then having to cut that row and paste on my other CASES-DONE titled worksheet, I'd like a macro to do that.
I want to run the macro after changing the status of several rows of data, from "pending" to "done". Then all those rows must be cut and pasted on the other worksheet.
Is that possible?
Thanks so much guys!
This is just a stab in the dark, but I've been handling something similar to this as of late.
Dim LastRow As Long
Range("1:1").AutoFilter Field:=(Row you have "Done" in), Criteria1:="Done"
LastRow = Cells(Rows.Count, 3).End(xlUp).Row
Range("CellRangeYouNeedCopied" & LastRow).Copy Destination:=Sheets("SheetX").Range(X,Y)
Basically this filters to only the rows with DONE in them, and copys and pastes them on whatever other sheet you decide to name. Just remember to replace all of the variables. I'm still pretty new at this, so I may be wrong but it's worth a shot!
Edit:You can also just record this as a macro, and then change the range so that it's variable using the Long variable.
You can also do it like this. More code, than the AutoFilter solution, but maybe more flexible.
Sub MoveDoneRows()
Dim nStatusCol As Integer
nStatusCol = 1
Dim i As Integer
i = 2
' select first row to insert rows into DONE sheet
Dim nInsertRow As Integer
Sheets("CASES-DONE").Select
Range("A1").Select
Selection.End(xlDown).Select
nInsertRow = ActiveCell.Row + 1
' move rows with status done
Dim sStatus As String
Dim sPasteRow As String
sStatus = Sheets("CASES-PENDING").Cells(i, nStatusCol).Value
While sStatus <> ""
If sStatus = "done" Then
' cut the current row from PENDING sheet
sPasteRow = i & ":" & i
Sheets("CASES-PENDING").Select
Rows(sPasteRow).Select
Selection.Cut
' paste into DONE sheet
Sheets("CASES-DONE").Select
Cells(nInsertRow, nStatusCol).Select
ActiveSheet.Paste
nInsertRow = nInsertRow + 1
' delete empty row from PENDING sheet
Sheets("CASES-PENDING").Select
Rows(sPasteRow).Select
Selection.Delete Shift:=xlUp
Else
i = i + 1
End If
sStatus = Sheets("CASES-PENDING").Cells(i, nStatusCol)
Wend
End Sub

Resources