VBA Code Help

Rob_010101

Board Regular
Joined
Jul 24, 2017
Messages
198
Office Version
  1. 365
Platform
  1. Windows
Hello,

I'll try and keep this as simple as possible.

I'm working on an absence tracker, tracking employee's absence in the current 12-month rolling period and the previous 12-month rolling period. So, 24 months in total.
1660320605173.png


The tracker is updated daily throughout the week and is EXTREMELY manual and time consuming.

I would like a piece of VBA code that runs automatically upon opening the workbook (it only needs to execute once per day) which does the following:
  1. 'Previous 12 months', any absence end dates that are before 24 months from today(), it deletes the row
  2. 'Current 12 months', any absence end dates that fall before 12 months from today(), it moves the row into the next available row of data on 'previous 12 months'.
The columns are laid out on both sheets as follows:

1660384710424.png


I hope this makes sense. Grateful for any help.

Kind Regards
Chris
 

Excel Facts

How can you turn a range sideways?
Copy the range. Select a blank cell. Right-click, Paste Special, then choose Transpose.
Could you try this code?
Be sure to test this on a copy of your data. :)



Edited to add:
To make this run automatically when opening the workbook, change the name of the macro from "Archive_data()" to "Workbook_Open()", and paste the macro in the "ThisWorkbook" folder of VisualBasic.




VBA Code:
Sub Archive_data()



' Set variables
    ' Move date
        Dim ToBeMovedDate As Long
        ToBeMovedDate = DateSerial(Year(Date) - 1, Month(Date), Day(Date))
    ' Delete date
        Dim ToBeDeletedDate As Long
        ToBeDeletedDate = DateSerial(Year(Date) - 2, Month(Date), Day(Date))
    ' Last row with data, current 12 months
        Dim LastRowCurrent12Months As String
        LastRowCurrent12Months = Sheets("Current 12 months").Cells(Sheets("Current 12 months").Rows.Count, "A").End(xlUp).Row
    ' Last row with data, previous 12 months
        Dim LastRowPrevious12Months As String
        LastRowPrevious12Months = Sheets("Previous 12 months").Cells(Sheets("Previous 12 months").Rows.Count, "A").End(xlUp).Row



' Remove existing filters , if applicable
    On Error Resume Next
        Sheets("Current 12 months").ShowAllData
        Sheets("Previous 12 months").ShowAllData
    On Error GoTo 0



'   o-------------------------------------------------------------o
'   |   MOVE LINES FROM CURRENT 12 MONTHS TO PREVIOUS 12 MONTHS   |
'   o-------------------------------------------------------------o

    ' Verify there are rows to be moved
        NumberOfRowsOnCurrent = WorksheetFunction.CountIfs(Sheets("Current 12 months").Range("J:J"), "<=" & ToBeMovedDate)

If NumberOfRowsOnCurrent > 0 Then
    ' Filter dates to be moved
        Sheets("Current 12 months").Range("A:N").AutoFilter Field:=10, Criteria1:="<=" & ToBeMovedDate
    ' Copy data to be moved to previous 12 months
        Sheets("Current 12 months").Select
        Sheets("Current 12 months").Range("A2:N" & LastRowCurrent12Months).Select
        Selection.Offset(0, 0).SpecialCells(xlCellTypeVisible).EntireRow.Copy
    ' Paste data into previous 12 months worksheet
        Sheets("Previous 12 months").Select
        Sheets("Previous 12 months").Range("A" & LastRowPrevious12Months + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
    ' Remove copied data from current 12 months
        Sheets("Current 12 months").Select
        Sheets("Current 12 months").Range("A2:N" & LastRowCurrent12Months).Select
        Selection.Offset(0, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
    ' Remove filter
        Sheets("Current 12 months").ShowAllData
End If



'   o-------------------------------------------------------------o
'   |            REMOVE LINES FROM PREVIOUS 12 MONTHS             |
'   o-------------------------------------------------------------o

    ' Verify there are rows to be removed
        NumberOfRowsOnPrevious = WorksheetFunction.CountIfs(Sheets("Previous 12 months").Range("J:J"), "<=" & ToBeDeletedDate)

If NumberOfRowsOnPrevious > 0 Then
    ' Filter dates to be deleted
        Sheets("Previous 12 months").Select
        Sheets("Previous 12 months").Range("A:N").AutoFilter Field:=10, Criteria1:="<=" & ToBeDeletedDate
    ' Select rows to be removed
        Sheets("Previous 12 months").Range("A2:N" & LastRowPrevious12Months).Select
    ' Delete rows
        Selection.Offset(0, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
    ' Remove filter
        Sheets("PRevious 12 months").ShowAllData
End If



End Sub
 
Last edited:
Upvote 0
Solution
Could you try this code?
Be sure to test this on a copy of your data. :)



Edited to add:
To make this run automatically when opening the workbook, change the name of the macro from "Archive_data()" to "Workbook_Open()", and paste the macro in the "ThisWorkbook" folder of VisualBasic.




VBA Code:
Sub Archive_data()



' Set variables
    ' Move date
        Dim ToBeMovedDate As Long
        ToBeMovedDate = DateSerial(Year(Date) - 1, Month(Date), Day(Date))
    ' Delete date
        Dim ToBeDeletedDate As Long
        ToBeDeletedDate = DateSerial(Year(Date) - 2, Month(Date), Day(Date))
    ' Last row with data, current 12 months
        Dim LastRowCurrent12Months As String
        LastRowCurrent12Months = Sheets("Current 12 months").Cells(Sheets("Current 12 months").Rows.Count, "A").End(xlUp).Row
    ' Last row with data, previous 12 months
        Dim LastRowPrevious12Months As String
        LastRowPrevious12Months = Sheets("Previous 12 months").Cells(Sheets("Previous 12 months").Rows.Count, "A").End(xlUp).Row



' Remove existing filters , if applicable
    On Error Resume Next
        Sheets("Current 12 months").ShowAllData
        Sheets("Previous 12 months").ShowAllData
    On Error GoTo 0



'   o-------------------------------------------------------------o
'   |   MOVE LINES FROM CURRENT 12 MONTHS TO PREVIOUS 12 MONTHS   |
'   o-------------------------------------------------------------o

    ' Verify there are rows to be moved
        NumberOfRowsOnCurrent = WorksheetFunction.CountIfs(Sheets("Current 12 months").Range("J:J"), "<=" & ToBeMovedDate)

If NumberOfRowsOnCurrent > 0 Then
    ' Filter dates to be moved
        Sheets("Current 12 months").Range("A:N").AutoFilter Field:=10, Criteria1:="<=" & ToBeMovedDate
    ' Copy data to be moved to previous 12 months
        Sheets("Current 12 months").Select
        Sheets("Current 12 months").Range("A2:N" & LastRowCurrent12Months).Select
        Selection.Offset(0, 0).SpecialCells(xlCellTypeVisible).EntireRow.Copy
    ' Paste data into previous 12 months worksheet
        Sheets("Previous 12 months").Select
        Sheets("Previous 12 months").Range("A" & LastRowPrevious12Months + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
    ' Remove copied data from current 12 months
        Sheets("Current 12 months").Select
        Sheets("Current 12 months").Range("A2:N" & LastRowCurrent12Months).Select
        Selection.Offset(0, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
    ' Remove filter
        Sheets("Current 12 months").ShowAllData
End If



'   o-------------------------------------------------------------o
'   |            REMOVE LINES FROM PREVIOUS 12 MONTHS             |
'   o-------------------------------------------------------------o

    ' Verify there are rows to be removed
        NumberOfRowsOnPrevious = WorksheetFunction.CountIfs(Sheets("Previous 12 months").Range("J:J"), "<=" & ToBeDeletedDate)

If NumberOfRowsOnPrevious > 0 Then
    ' Filter dates to be deleted
        Sheets("Previous 12 months").Select
        Sheets("Previous 12 months").Range("A:N").AutoFilter Field:=10, Criteria1:="<=" & ToBeDeletedDate
    ' Select rows to be removed
        Sheets("Previous 12 months").Range("A2:N" & LastRowPrevious12Months).Select
    ' Delete rows
        Selection.Offset(0, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
    ' Remove filter
        Sheets("PRevious 12 months").ShowAllData
End If



End Sub
It works like a charm.

Thank you so much for your time, it's greatly appreciated.

Kind Regards
Chris
 
Upvote 0
No problem, and thank you for marking this a solution. :)
The "remove existing filters" part

Does that clear all applied filters before moving the row across? I'm asking because I've had issues before with similar VBA code working on another sheet in a different workbook where the data is filtered. Basically, it copied to a random row which wasn't at the bottom of the data. The workaround looked way more complicated than this, so I'm just interested.

The code with the fix is below. You might tell me different but I understand that it basically moves a row across to another sheet based on the value selected in a drop-down menu. It also does something to the new sheet if the filters are applied, so that it adds the row to the next available row, even if filters are applied.

VBA Code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim fromRow%, archiveRow%, archiveList As Worksheet

    If Target.Cells.Count > 1 Then Exit Sub
 
    If Not Application.Intersect(Target, Range("O2:O500000")) Is Nothing Then 'amend this range address to your
        Set archiveList = ThisWorkbook.Worksheets("Archive")
            If Target.Value = "Archive" Then
                fromRow = ActiveCell.Row
               
                With archiveList
                    If .FilterMode Then
                        Dim strMatch As String
                        strMatch = "match" & Replace("(2,1/(a:a>""""),1)", "a:a", .AutoFilter.Range.Cells(1).EntireColumn.Address(0, 0, 1, 1))
                        archiveRow = Evaluate(strMatch) + 1
                    Else
                        archiveRow = archiveList.Cells(archiveList.Rows.Count, 1).End(3).Row + 1
                    End If
                End With
               
                Range(Cells(fromRow, 1), Cells(fromRow, 15)).Copy archiveList.Cells(archiveRow, 1)
                Rows(fromRow).EntireRow.Delete
            End If
    End If
End Sub

It's not that the above doesn't work, it's more that I'm trying to teach myself how to write VBA code and I'm keen to learn from experienced people

Kind Regards
 
Upvote 0
This reply will be to explain my own code.
The code you copied in the last mail will be a seperate post. Kind a working out what it's doing.


Anyway, my code first removes all existing filters to make sure nothing is hidden, so no hidden cells might be overwritten.


The rows with "showAllData" will remove any filter.
In case there is no filter, the macro will get an error.
That's why I begin the code with "on Error resume next". This code will skip all error messages.
The error messages will be skipped, until the error coding is turned back on, hence "On error GoTo 0".
VBA Code:
    On Error Resume Next
        Sheets("Current 12 months").ShowAllData
        Sheets("Previous 12 months").ShowAllData
    On Error GoTo 0


After removing the filters, I identify which is the last row with data.
It does so by looking at the last row with data in column A.
NOTE: because of this, the macro does presume that every row with data has something in column A!
If the last row(s) with data has no data in column A, then you will still overwrite data!
VBA Code:
        Dim LastRowPrevious12Months As String
        LastRowPrevious12Months = Sheets("Previous 12 months").Cells(Sheets("Previous 12 months").Rows.Count, "A").End(xlUp).Row


Having identified the last row with data, I can then paste the data in the next row.
That's why my code pastes the information in column A, row LastRowPrevious12Months + 1.
VBA Code:
Sheets("Previous 12 months").Select
        Sheets("Previous 12 months").Range("A" & LastRowPrevious12Months + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
 
Upvote 0
Going over your code, let's start with one potential issue. Your code will aways work with up to 500.000 rows.
If you have more rows, then 500.000 rows, then you will miss rows 500.001 and beyond.
If you fewer rows, then your formula might be needlessly slow. (though to be fair, I don't think the speed will make much of a difference)
VBA Code:
If Not Application.Intersect(Target, Range("O2:O500000")) Is Nothing Then

I would change that, so the macro identifies the last row and uses that as a variable inside the macro.
VBA Code:
LastRowData = Sheets(ENTERSHEETNAMEHERE).Cells(sheets(ENTERSHEETNAMEHERE).Rows.Count, "A").End(xlUp).Row
If Not Application.Intersect(Target, Range("O2:O" & LastRowData)) Is Nothing Then



Going through the macro, it looks like you have the drop-down list in column O.
The macro is written so that whenever something changes in the entire worksheet, the macro will run.

The code will first check if there is something in column O of the active row.
If there is not, the macro will skip all next steps and close.
If there is something in there, the macro will continue.
VBA Code:
 If Not Application.Intersect(Target, Range("O2:O500000")) Is Nothing Then

This code will check if the entry in the column O says "Archive" (that's the Target.value).
If it is not archive, the macro will skip all next steps and close.
If it does say "Archive", then the macro will take the active row and places it in the variables list as "fromRow".
It also places your worksheet called "Archive" and places it in the variables list as "Archivelist"
VBA Code:
Set archiveList = ThisWorkbook.Worksheets("Archive")
If Target.Value = "Archive" Then
fromRow = ActiveCell.Row

Having basically "copied" your desired row into memory, it then continues.
It goes to the Archivelist, and check if it has been filtered.
VBA Code:
              With archiveList
                    If .FilterMode Then

If it has been filtered, it will count how many cells in column A:A are not empty. , and thus identifies the first EMPTY row.
This empty row is copied into the variables list as "ArchiveRow".
I can't really go into detail explaining how it does what it does. I am not exactly sure how it does what it does, but I do know it counts the number of rows that are not empty.
VBA Code:
                        Dim strMatch As String
                        strMatch = "match" & Replace("(2,1/(a:a>""""),1)", "a:a", .AutoFilter.Range.Cells(1).EntireColumn.Address(0, 0, 1, 1))
                        archiveRow = Evaluate(strMatch) + 1

If there is no filter, then the last visible row is taken.
This empty row is copied into the variables list as "ArchiveRow".
To be honest, I am not quite sure what the 3 refers to in End(3).
VBA Code:
                    Else
                        archiveRow = archiveList.Cells(archiveList.Rows.Count, 1).End(3).Row + 1
                    End If
                End With

Having decided where the changed row has to go, it now copies the changed row into the archive.
It takes the contents of the change row (FROMROW) from column 1 through column 15, and copies it into the first emtpy row of the archive. That's the "ArchiveRow" identified earlier.
VBA Code:
                Range(Cells(fromRow, 1), Cells(fromRow, 15)).Copy archiveList.Cells(archiveRow, 1)

And it closes everything of by deleting the row that was changed:
VBA Code:
Rows(fromRow).EntireRow.Delete
 
Upvote 0
Going over your code, let's start with one potential issue. Your code will aways work with up to 500.000 rows.
If you have more rows, then 500.000 rows, then you will miss rows 500.001 and beyond.
If you fewer rows, then your formula might be needlessly slow. (though to be fair, I don't think the speed will make much of a difference)
VBA Code:
If Not Application.Intersect(Target, Range("O2:O500000")) Is Nothing Then

I would change that, so the macro identifies the last row and uses that as a variable inside the macro.
VBA Code:
LastRowData = Sheets(ENTERSHEETNAMEHERE).Cells(sheets(ENTERSHEETNAMEHERE).Rows.Count, "A").End(xlUp).Row
If Not Application.Intersect(Target, Range("O2:O" & LastRowData)) Is Nothing Then



Going through the macro, it looks like you have the drop-down list in column O.
The macro is written so that whenever something changes in the entire worksheet, the macro will run.

The code will first check if there is something in column O of the active row.
If there is not, the macro will skip all next steps and close.
If there is something in there, the macro will continue.
VBA Code:
 If Not Application.Intersect(Target, Range("O2:O500000")) Is Nothing Then

This code will check if the entry in the column O says "Archive" (that's the Target.value).
If it is not archive, the macro will skip all next steps and close.
If it does say "Archive", then the macro will take the active row and places it in the variables list as "fromRow".
It also places your worksheet called "Archive" and places it in the variables list as "Archivelist"
VBA Code:
Set archiveList = ThisWorkbook.Worksheets("Archive")
If Target.Value = "Archive" Then
fromRow = ActiveCell.Row

Having basically "copied" your desired row into memory, it then continues.
It goes to the Archivelist, and check if it has been filtered.
VBA Code:
              With archiveList
                    If .FilterMode Then

If it has been filtered, it will count how many cells in column A:A are not empty. , and thus identifies the first EMPTY row.
This empty row is copied into the variables list as "ArchiveRow".
I can't really go into detail explaining how it does what it does. I am not exactly sure how it does what it does, but I do know it counts the number of rows that are not empty.
VBA Code:
                        Dim strMatch As String
                        strMatch = "match" & Replace("(2,1/(a:a>""""),1)", "a:a", .AutoFilter.Range.Cells(1).EntireColumn.Address(0, 0, 1, 1))
                        archiveRow = Evaluate(strMatch) + 1

If there is no filter, then the last visible row is taken.
This empty row is copied into the variables list as "ArchiveRow".
To be honest, I am not quite sure what the 3 refers to in End(3).
VBA Code:
                    Else
                        archiveRow = archiveList.Cells(archiveList.Rows.Count, 1).End(3).Row + 1
                    End If
                End With

Having decided where the changed row has to go, it now copies the changed row into the archive.
It takes the contents of the change row (FROMROW) from column 1 through column 15, and copies it into the first emtpy row of the archive. That's the "ArchiveRow" identified earlier.
VBA Code:
                Range(Cells(fromRow, 1), Cells(fromRow, 15)).Copy archiveList.Cells(archiveRow, 1)

And it closes everything of by deleting the row that was changed:
VBA Code:
Rows(fromRow).EntireRow.Delete
I've learned quite a lot from this. Hopefully, I can start teaching myself how to do it

Thanks very much for taking the time to explain.
 
Upvote 0
Could you try this code?
Be sure to test this on a copy of your data. :)



Edited to add:
To make this run automatically when opening the workbook, change the name of the macro from "Archive_data()" to "Workbook_Open()", and paste the macro in the "ThisWorkbook" folder of VisualBasic.




VBA Code:
Sub Archive_data()



' Set variables
    ' Move date
        Dim ToBeMovedDate As Long
        ToBeMovedDate = DateSerial(Year(Date) - 1, Month(Date), Day(Date))
    ' Delete date
        Dim ToBeDeletedDate As Long
        ToBeDeletedDate = DateSerial(Year(Date) - 2, Month(Date), Day(Date))
    ' Last row with data, current 12 months
        Dim LastRowCurrent12Months As String
        LastRowCurrent12Months = Sheets("Current 12 months").Cells(Sheets("Current 12 months").Rows.Count, "A").End(xlUp).Row
    ' Last row with data, previous 12 months
        Dim LastRowPrevious12Months As String
        LastRowPrevious12Months = Sheets("Previous 12 months").Cells(Sheets("Previous 12 months").Rows.Count, "A").End(xlUp).Row



' Remove existing filters , if applicable
    On Error Resume Next
        Sheets("Current 12 months").ShowAllData
        Sheets("Previous 12 months").ShowAllData
    On Error GoTo 0



'   o-------------------------------------------------------------o
'   |   MOVE LINES FROM CURRENT 12 MONTHS TO PREVIOUS 12 MONTHS   |
'   o-------------------------------------------------------------o

    ' Verify there are rows to be moved
        NumberOfRowsOnCurrent = WorksheetFunction.CountIfs(Sheets("Current 12 months").Range("J:J"), "<=" & ToBeMovedDate)

If NumberOfRowsOnCurrent > 0 Then
    ' Filter dates to be moved
        Sheets("Current 12 months").Range("A:N").AutoFilter Field:=10, Criteria1:="<=" & ToBeMovedDate
    ' Copy data to be moved to previous 12 months
        Sheets("Current 12 months").Select
        Sheets("Current 12 months").Range("A2:N" & LastRowCurrent12Months).Select
        Selection.Offset(0, 0).SpecialCells(xlCellTypeVisible).EntireRow.Copy
    ' Paste data into previous 12 months worksheet
        Sheets("Previous 12 months").Select
        Sheets("Previous 12 months").Range("A" & LastRowPrevious12Months + 1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
    ' Remove copied data from current 12 months
        Sheets("Current 12 months").Select
        Sheets("Current 12 months").Range("A2:N" & LastRowCurrent12Months).Select
        Selection.Offset(0, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
    ' Remove filter
        Sheets("Current 12 months").ShowAllData
End If



'   o-------------------------------------------------------------o
'   |            REMOVE LINES FROM PREVIOUS 12 MONTHS             |
'   o-------------------------------------------------------------o

    ' Verify there are rows to be removed
        NumberOfRowsOnPrevious = WorksheetFunction.CountIfs(Sheets("Previous 12 months").Range("J:J"), "<=" & ToBeDeletedDate)

If NumberOfRowsOnPrevious > 0 Then
    ' Filter dates to be deleted
        Sheets("Previous 12 months").Select
        Sheets("Previous 12 months").Range("A:N").AutoFilter Field:=10, Criteria1:="<=" & ToBeDeletedDate
    ' Select rows to be removed
        Sheets("Previous 12 months").Range("A2:N" & LastRowPrevious12Months).Select
    ' Delete rows
        Selection.Offset(0, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
    ' Remove filter
        Sheets("PRevious 12 months").ShowAllData
End If



End Sub
Hello Again

Sorry to ask this. I was asked by my boss to add another column and the VB code has stopped working completely. I tried removing the column but it's still not working.

Absence end date is still in column J but now columns go to "O". I've spent a few hours playing around with the code but I just can't get it to work again.

Columns on both sheets are now:

1660635782219.png


Kind Regards
Chris
 
Upvote 0
Hello Again

Sorry to ask this. I was asked by my boss to add another column and the VB code has stopped working completely. I tried removing the column but it's still not working.

Absence end date is still in column J but now columns go to "O". I've spent a few hours playing around with the code but I just can't get it to work again.

Columns on both sheets are now:

View attachment 71683

Kind Regards
Chris
I've managed to fix it :).
 
Upvote 0

Forum statistics

Threads
1,223,157
Messages
6,170,418
Members
452,325
Latest member
BlahQz

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top