How to Delete rows according to criteria in cells - excel

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

Related

How to add Date every day to my first blank row

I would like every day, when I open excel, that my excel would add a today's date to it. I have this code, but it isn't working, sometimes it does what it's supposed to and sometimes it skips a line, any help please?
Sub Stretching()
'This procedure will run each time you open the workbook
'Specify the required worksheet name in double quotes
Dim ws As Worksheet
Set ws = Sheets("Stretching")
'Get the last row number filled with a value in Column A
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
'Check if the last entered date is the same as the current date, if so, exit
'You need this check to see if you close the workbook then open it on the same day
'so that the code does not enter the same date again in a new row.
If ws.Cells(lastRow, 1).Value = Date Then Exit Sub
'Fill a new row in Column A with the current date
If IsEmpty(Cells(lastRow, 1)) Then
ws.Cells(lastRow, 1).Value = Date
Else
ws.Cells(lastRow, 1).Offset(1, 0).Value = Date
End If
End Sub
Some suggestions on your code:
Fully qualifying the ranges help you avoiding inconsistent results. This means, you can be running the procedure when an active sheet is different than the one you are targeting, and this line: Cells(Rows.Count, 1).End(xlUp).Row would return a different "last row" than the one you'd expect
Also try to use variable names that are easily understandable. For example, ws vs targetSheet
Please try this code and let me know if it works:
Public Sub Stretching()
'This procedure will run each time you open the workbook
'Specify the required worksheet name in double quotes
Dim targetSheet As Worksheet
Set targetSheet = ThisWorkbook.Sheets("Stretching")
'Get the last row number filled with a value in Column A
Dim lastRow As Long
lastRow = targetSheet.Cells(targetSheet.Rows.Count, 1).End(xlUp).Row
'Check if the last entered date is the same as the current date, if so, exit
'You need this check to see if you close the workbook then open it on the same day
'so that the code does not enter the same date again in a new row.
If targetSheet.Cells(lastRow, 1).Value = Date Then Exit Sub
'Fill a new row in Column A with the current date
If IsEmpty(targetSheet.Cells(lastRow, 1)) Then
targetSheet.Cells(lastRow, 1).Value = Date
Else
targetSheet.Cells(lastRow, 1).Offset(1, 0).Value = Date
End If
End Sub

How to copy data between two defined dates to new worksheet using VBA?

I am trying to copy data from a "Data" worksheet into a already created worksheet called "DateData". I want the user to be able to enter in a Start Date ("L15") and End Date ("L16") in a separate worksheet called "No Entry". On a button click...Then the data in "Data" worksheet is pulled into the "DateData" Worksheet, only including records between those dates (including the start and entry date). I hope that makes sense haha
I have tried the below but keep getting errors. The first being a "Sort method of Range class failed 1004". The code below also doesn't use the preset worksheet to copy data but creates a sheet at the end of all worksheets (which I don't want).
The "Data" worksheet has titles all in row 1 and data starts from A2 onwards...It has 19 columns of titles (so data filled) and the date that I want it looking for is in column G..G1=Title, G2 = Date starts. Date format = dd/mm/yyyy
How would I go about doing this? Any help would be so grateful. Thank you
Private Sub CommandButton2_Click()
Application.ScreenUpdating = False
Dim StartDate, EndDate As Date
Dim MainWorksheet As Worksheet
StartDate = Sheets("NoEntry").Range("L15").Value
EndDate = Sheets("NoEntry").Range("L16").Value
Set MainWorksheet = Worksheets("Data")
MainWorksheet.Activate
Range("G1").CurrentRegion.Sort key1:=Range("G1"), order1:=xlAscending, Header:=xlYes
Range("G1").CurrentRegion.AutoFilter Field:=7, Criteria1:=">=" & StartDate, Operator:=xlAnd,
Criteria2:="<=" & EndDate
ActiveSheet.AutoFilter.Range.Copy
Worksheets.Add after:=Worksheets(Worksheets.Count)
ActiveSheet.Paste
Selection.Columns.AutoFit
Range("G1").Select
MainWorksheet.Activate
Selection.AutoFilter
Sheets("NoEntry").Activate
End Sub
"DateData"
"Data"
So as you can see from the "Data" worksheet I have sorted the data but because it has blanks they are at the bottom (as in there are no dates in the G column for it). This was before validation so this happened
And what copies over onto the "DateData" worksheet is only the records with blank dates.
Sorry for the black filled records as they are private information. I hope that makes sense.
First, see How to avoid using Select in Excel VBA to learn how to avoid using select in your code. There is almost no necessary case in using it.
See below notes for the code I provide (now tested!).
1) You are having an issue where a worksheet is being added and you are not aware how/ why and you are uncertain of your destination for your data. To overcome this, it is a common practice to explicitly define your worksheet objects. This makes it easier for you to understand, while also allowing for less scope for error. I have qualified the worksheets as wsData for “Data worksheet”, wsDate for “DateData worksheet” and wsNoEntry for “No Entry worksheet”. Do you see how easy it is to understand now?
2) Make sure that the dates in your data set are stored as “Date” type values. You can do this under the number formatting ribbon.
3) I have chosen to use an array to loop through. Depending on how big your data set is, this will be a much faster way to loop through to get the start and end date
4) This approach assumes your data is sorted by the Date column (G)
Sub CopyDataUsingDateRange()
Application.ScreenUpdating = False
Dim wsData As Worksheet, wsDate As Worksheet, wsNoEntry As Worksheet
Dim dSDate As Date, dEDate As Date
Dim lRowStart As Long, lRowEnd As Long
Dim aData() As Variant
Dim i As Long
'set the worksheet objects
Set wsData = ThisWorkbook.Sheets("Data")
Set wsDate = ThisWorkbook.Sheets("DateData")
Set wsNoEntry = ThisWorkbook.Sheets("No Entry")
'required variables
dSDate = wsNoEntry.Range("L15").Value
dEDate = wsNoEntry.Range("L16").Value
'set the array - you can make this dynamic!
aData = wsData.Range("A1:Z1000").Value
'for loop to find start
For i = 1 To 1000
If aData(i, 7) = dSDate Then
lRowStart = i
Debug.Print "Start row = " & lRowStart
Exit For
End If
Next i
'now loop backwards to find end date
For i = 1000 To 1 Step -1
If aData(i, 7) = dEDate Then
lRowEnd = i
Debug.Print "End row = " & lRowEnd
Exit For
End If
Next i
'now we have start and end dates
'going to use copy/ paste for simplicity
wsData.Range("A" & lRowStart, "Z" & lRowEnd).Copy
'paste in date sheet
wsDate.Range("A1").PasteSpecial Paste:=xlPasteValues
'clear clipboard
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Hope this helps, mostly with understanding so you can leverage for future use!
Consider avoiding the use of constant .Select and .Activate. Instead, manage processes with Set variables or in a With context. Additionally, the filter copy method needs to be handled differently namely on visible and non-blank cell results of filtered worksheet.
Dim StartDate As Date, EndDate As Date
Dim MainWorksheet As Worksheet, NewWorkSheet As Worksheet
StartDate = Sheets("NoEntry").Range("L15").Value
EndDate = Sheets("NoEntry").Range("L16").Value
Set MainWorksheet = Worksheets("Data")
With MainWorksheet
' SORT RANGE
.Range("G1").CurrentRegion.Sort key1:=.Range("F1"), order1:=xlAscending, Header:=xlYes
Set NewWorkSheet = Worksheets.Add(after:=Worksheets(Worksheets.Count))
With .Range("$A:$G")
' SORT RANGE
.AutoFilter Field:=7, Criteria1:=">=" & StartDate, Operator:=xlAnd, _
Criteria2:="<=" & EndDate
' COPY VISIBLE AND NON-BLANK CELLS TO NEW WORKSHEET
Application.Intersect(.SpecialCells(xlCellTypeVisible), _
.SpecialCells(xlCellTypeConstants)).Copy _
Destination:=NewWorkSheet.Range("A1")
End With
' REMOVE FILTER
.Cells.AutoFilter
End With
Sheets("NoEntry").Activate
Set MainWorksheet = Nothing: Set NewWorkSheet = Nothing

Find row with date, active cell in fixed column, and write timestamp

I want create a excel to record some times (enter to work, exit to dinner...). I tought the best way to do it is excel with vba code.
I put some bottons (like in photo I upload) to record some important times, and I create a table with days in month and events to record.
But, the problem is in vba code. I'm very inexpert in excel vba and only get this code:
Sub time()
ActiveCell.Value = Now
End Sub
In active cell, this code write timestamp.... But I want more advanced code. For example, I have button 'Enter to work', and I want when I press it:
Excel find row refers to today date
Find column 'Enter to work'
And write timestamp (hour:minute:second) in this cell
I don't know how to do this. Can anyone help me?
You can do something like below. First you will get the last row of your date than just use a loop to cycle through and compare the date on the sheet with the Now() function that returns today's date. Then you can use the offset to write the time to next cell. You can assign the macro to the buttons on the spredsheet and will be triggered each time. I guess you can put another if statement to check if there are values in the cell before attempting to write just to avoid overriding data. Note the date format on the sheet should be 14/05/2019.
Option Explicit
Sub FillInForm()
Dim WS As Worksheet
Dim i As Long
Dim LRow As Long
Dim dateFormatter As String
Dim xDate As Date
Set WS = ActiveSheet
dateFormatter = Format(Now, "dd/mm/yyyy")
xDate = CDate(dateFormatter)
With WS
LRow = .Range("B" & .Rows.Count).End(xlUp).Row
For i = 5 To LRow
If CDate(.Range("B" & i).value) = CDate(xDate) Then
If .Range("B" & i).Offset(0, 1).value = vbNullString Then
.Range("B" & i).Offset(0, 1).value = VBA.DateTime.Time
End If
End If
Next i
End With
End Sub

copy data based on criteria to another sheet and clear the contents

This code is working to copy the filtered data of "Award" column marked "Yes" to another sheet; however, I'm receiving an error of "Type Mismatch." I'm not 100% now that the code is working properly to filter the data and copy correctly. I currently have 23 rows of test data for proper functionality. If I only put one row of data, then it doesn't copy and paste the data correctly. I am left with the copied 1st row of data plus the 2nd empty row of data. Additionally, it is not clearing the contents of the rows after the paste, so I may add new data as the days progress.
Sub CopySheet()
Dim i As Integer
Dim LastRow As Integer
Dim Search As String
Dim Column As Integer
Sheets("MasterData").Activate
Sheets("MasterData").Range("A1").Select
'Sets an Autofilter to sort out only your Yes rows.
Selection.AutoFilter
'Change Field:=5 to the number of the column with your Y/N.
Sheets("MasterData").Range("$A$1:$G$200000").AutoFilter Field:=7, Criteria1:="Yes"
'Finds the last row
LastRow = Sheets("MasterData").Cells(Sheets("MasterData").Rows.Count, "A").End(xlUp).row
i = 1
'Change the 3 to the number of columns you got in Sheet2
Do While i <= 11
Search = Sheets("ActiveJobStatus").Cells(1, i).Value
Sheets("MasterData").Activate
'Update the Range to cover all your Columns in MasterData.
If IsError(Application.Match(Search, Sheets("MasterData").Range("A1:G1"), 0)) Then
'nothing
Else
Column = Application.Match(Search, Sheets("MasterData").Range("A1:G1"), 0)
Sheets("MasterData").Cells(2, Column).Resize(LastRow, 1).Select
Selection.Copy
Sheets("ActiveJobStatus").Activate
Sheets("ActiveJobStatus").Cells(2, i).Select
ActiveSheet.Paste
End If
i = i + 1
Loop
'Clear all Y/N = Y
'Update the Range to cover all your Columns in MasterData.
Sheets("MasterData").Activate
Column = Application.Match("Award", Sheets("MasterData").Range("A1:F1"), 0)
Sheets("MasterData").Cells(2, Column).Resize(LastRow, 1).Select
Selection.ClearContents
End Sub
Sorry to change your code up so much, but it looks like you might be over-complicating how to do it.
This is some code from a previous question I answered where someone wanted to highlight a specific range whenever the word "Total" was found.
I changed the find to "Yes". Change the SearchRange to your column. (I think G is right).
Also, for future reference, Select should [almost never] be used.
It slows down code execution quite a bit and is not required.
I know the macro recorder likes to use it, but everything can be referenced without using select.
Brief example:
Sheets("ActiveJobStatus").Activate
Sheets("ActiveJobStatus").Cells(2, i).Select
ActiveSheet.Paste
Can Be replaced by:
Sheets("ActiveJobStatus").Cells(2, i).Paste
This code is working to copy the filtered data of "Award" column marked "Yes" to another sheet.
Sub CopyAwardsToActiveJobStatusSheet()
Dim SearchRange, First, Finder As Range
Dim PasteRow as Integer 'Add this to increment the rows we paste your data to
Set SearchRange = Sheets("MasterData").Range("G:G") 'Search This Range for "Yes"
Set Finder = SearchRange.Find("Yes") 'This is what we're looking for
If Finder Is Nothing Then Exit Sub 'We didn't find any "Yes" so we're done
'Drastically increases speed of every macro ever
'(well, when the sheets are modified at least - and it doesn't hurt)
Application.ScreenUpdating = False
First = Finder.Address 'Grab the address of the first "Yes" so we know when to stop
'Get the last row of column "A" on ActiveJobStatusSheet and start pasting below it
PasteRow = Sheets("ActiveJobStatus").Cells(Sheets("ActiveJobStatus").Rows.Count, "A").End(xlUp).Row + 1
Do
'Copy the entire row and paste it into the ActiveJobStatus sheet
'Column A and PasteRow (the next empty row on the sheet)
'You can change these if needed
Finder.EntireRow.Copy Sheets("ActiveJobStatus").Range("A" & PasteRow)
'If you just want A:G, you can use this instead:
'Finder returns the cell that contains "Yes",
'So we offset/resize to get the 6 cells before it and just copy that
'Resize doesn't like negative numbers so we have to combine:
'Finder.Offset(,-6).Resize(,7).Copy Sheets("ActiveJobStatus").Range("A" & PasteRow)
'Look for the next "Yes" after the one we just found
Set Finder = SearchRange.FindNext(after:=Finder)
PasteRow = PasteRow + 1 'Faster than looking for the end again
'Do this until we are back to the first address
Loop While Not Finder Is Nothing And Finder.Address <> First
'Clear MasterData
Sheets("MasterData").Range("A2:G" & Sheets("MasterData").UsedRange.Rows.Count).ClearContents
Application.ScreenUpdating = True 'Drastically increases speed of every macro ever.
End Sub
Just the code:
Sub CopyAwardsToActiveJobStatusSheet()
Dim SearchRange, First, Finder As Range
Dim PasteRow as Integer
Set SearchRange = Sheets("MasterData").Range("G:G")
Set Finder = SearchRange.Find("Yes")
If Finder Is Nothing Then Exit Sub
Application.ScreenUpdating = False
First = Finder.Address
PasteRow = Sheets("ActiveJobStatus").Cells(Sheets("ActiveJobStatus").Rows.Count, "A").End(xlUp).Row + 1
Do
Finder.EntireRow.Copy Sheets("ActiveJobStatus").Range("A" & PasteRow)
Set Finder = SearchRange.FindNext(after:=Finder)
PasteRow = PasteRow + 1
Loop While Not Finder Is Nothing And Finder.Address <> First
Sheets("MasterData").Range("A2:G" & Sheets("MasterData").UsedRange.Rows.Count).ClearContents
Application.ScreenUpdating = True
End Sub
Results:
MasterData Sheet:
ActiveJobStatus Sheet:

How to copy only rows with data from one worksheet to another in a different workbook?

I can pull together a decent macro that does what I need but I forgot that the range will change everyday.
To be specific the row count will get higher.
Right now my macro goes through and hides any row that doesn't have today's date and then copies a set range to a worksheet in a different workbook.
The only problem I have is that range will change everyday, so I figure I need a way to copy only rows with data in them once the rest are hidden and then paste them to the other workbook.
Sub automate()
Dim cell As Range
For Each cell In Range("AB2:AB30000")
If cell.Value < Date And cell.Value <> Empty Then cell.EntireRow.Hidden = True
Next
Range("K28336:K28388,O28336:O28388,P28336:P28388,Q28336:Q28388,R28336:R28388,S28336:S28388,T28336:T28388,U28336:U28388,V28336:V28388,Y28336:Y28388,AA28336:AA28388,AB28336:AB28388").Select
Selection.Copy
Workbooks.Open ("\\gvwac09\Public\Parts\Test\2014 IPU.xlsx")
Sheets("Historical Data").Activate
ActiveSheet.Range("c1").End(xlDown).Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteFormats
ActiveSheet.Paste
This is my macro so far. I'm sorry if I didn't format this post correctly, new to this.
I do not understand exacting what you are attempting but I believe I can give you some useful pointers.
I do not explain the statements I use in the code below. Look them up in the Visual Basic Editor's Help or try searching the web for "Excel VBA xxxxx". Come back with questions if necessary but the more you can discover for yourself, the quicker your skills will develop.
Firstly you need to find the last row containing data. Examining every row down to AB30000 just wastes time. Macro Demo1 below demonstrates two techniques. There are more techniques for finding the last row, none of which are appropriate in every situation. Search StackOverflow for "[excel-vba] find last row". There are lots of relevant questions and answers although the first technique I use is far and away the most popular.
General advice: If you can break your requirement down to a sequence of single issues (such as "find last row"), you will find it easier to search StackOverflow for an answer.
Always include Application.ScreenUpdating = False at the start of your macros if you are going to amend a worksheet. Without this statement, everytime you hide a row, Excel repaints the screen.
I have created some test data which I hope is representative of your data. I have two worksheets Source and Dest. Source contains the full set of data. I copy the selected rows to Dest.
I have used Auto Filter which will be much faster than your technique if it will give you the effect you seek. Play with Auto Filter from the keyboard. If you can get the effect you seek, turn on the Macro Recorder, use Auto Filter to get the selection you seek and switch the Macro Recorder off. Adjust the Macro Recorder's statements to remove Selection and replace the corresponding statements in Demo2.
The secret of Demo2 is Set Rng = .AutoFilter.Range.SpecialCells(xlCellTypeVisible) which sets Rng to the visible rows. If you cannot get Auto Filter to work as you wish and you decide to use your current technique to set uninteresting rows invisible, keep this statement to get the remaining rows. However, I think macro Demo3 uses a better technique.
Option Explicit
Sub demo1()
Dim ColLast As Long
Dim Rng As Range
Dim RowLast As Long
Application.ScreenUpdating = False
With Worksheets("Source")
' This searches up from the bottom of column AB for a cell with a value.
' It is the VBA equivalent of placing the cursor at the bottom of column AB
' and clicking Ctrl+Up.
RowLast = .Cells(Rows.Count, "AB").End(xlUp).Row
Debug.Print "Last row with value in column AB: " & RowLast
' This searches for the last cell with a value.
Set Rng = .Cells.Find(What:="*", After:=.Range("A1"), SearchDirection:=xlPrevious)
If Rng Is Nothing Then
' Worksheet is empty
Else
RowLast = Rng.Row
ColLast = Rng.Column
Debug.Print "Last cell with value is: (" & RowLast & ", " & ColLast & _
") = " & Replace(Rng.Address, "$", "")
End If
End With
End Sub
Sub Demo2()
Dim Rng As Range
Dim SearchDate As String
SearchDate = "14-May-14"
Application.ScreenUpdating = False
With Sheets("Source")
.Cells.AutoFilter
.Cells.AutoFilter Field:=28, Criteria1:=SearchDate
Set Rng = .AutoFilter.Range.SpecialCells(xlCellTypeVisible)
End With
' Rng.Address has a maximum length of a little under 256 characters.
' Rng holds the addresses of all the visible rows but you cannot display
' all those addresses in an easy manner. However, this is only to give
' you an idea of what is in Rng; the Copy statement below uses the full
' set of addresses.
Debug.Print "Visible rows: " & Rng.Address
Rng.Copy Worksheets("Dest").Range("A1")
End Sub
Sub Demo3()
Dim RngToBeCopied As Range
Dim RowCrnt As Long
Dim RowLast As Long
Dim SearchDate As Long
' Excel holds dates as integers and times as fractions.
SearchDate = CLng(DateValue("20 May 2014"))
With Worksheets("Source")
RowLast = .Cells(Rows.Count, "AB").End(xlUp).Row
' Include header row in range to be copied
Set RngToBeCopied = .Rows(1)
For RowCrnt = 2 To RowLast
If .Cells(RowCrnt, "AB").Value = SearchDate Then
Set RngToBeCopied = Union(RngToBeCopied, .Rows(RowCrnt))
End If
Next
End With
Debug.Print RngToBeCopied.Address
RngToBeCopied.Copy Worksheets("Dest").Range("A1")
End Sub

Resources