I have the below data in an excel spreadsheet
I want to cycle through column B and capture consecutive Paid Leaves for each employee and generate a another aggregated table like the below one:
So for each employee to calculate the days of consecutive Paid Leaves in an extra row together with a Start and an End date (Start the first day and End the last day of the consecutive Leave).
I haven't managed to think of a way to tackle that. I have minimum experience in VBA and this logic seems very complex to my knowledge so far. I would appreciate if anyone could help.
This was getting too long for a comment so here's to help you on your way: We try not to just make things for others without OP even trying to code anything. To get into VBA, try out things with the macro reader, then read up on How to avoid using Select in Excel VBA and perhaps start off with https://www.simplilearn.com/tutorials/excel-tutorial/excel-vba so you understand a bit what everything does/is for. As for logic getting from initial to end state:
Then if you're still stuck after trying all this, come back and we'll be happy to help:)
EDIT After seeing you actually tried out something, here's my revised version of it with (hopefully) understandable commentary, I've used similar code like this before and I don't know anymore why I opted for a for-loop instead of a while but either could work in this case.
Sub paid_leave()
Dim wb As Workbook 'declare all your variables upfront and go through your code with F8 from the VBE (VB environment)
Dim ws As Worksheet, ws2 As Worksheet
Dim CurrentRow As Long, Lastrow As Long, Lastrow2 As Long, amtDays As Long, i As Long
Set wb = ActiveWorkbook
Set ws = wb.Sheets("Blad1") 'a lot easier to write the rest of the code with
Set ws2 = wb.Sheets("Blad2") 'and it helps when you need the change the name of the sheet/workbook
CurrentRow = 2
Lastrow = ws.Range("B" & Rows.Count).End(xlUp).Row
amtDays = 1
For i = CurrentRow To Lastrow 'could technically work with a while loop since we're not using the i and increment our CurrentRow as well
If ws.Range("B" & CurrentRow).Value2 = "Paid Leave" Then
Lastrow2 = ws2.Range("A" & Rows.Count).End(xlUp).Row
ws2.Range("A" & Lastrow2 + 1).Value2 = ws.Range("C" & CurrentRow).Value2 'start and endrow not necessary this way
ws2.Range("B" & Lastrow2 + 1).Value2 = ws.Range("B" & CurrentRow).Value2
ws2.Range("D" & Lastrow2 + 1).Value2 = ws.Range("A" & CurrentRow).Value2
'Do While CurrentRow <> Lastrow 'this is a bad condition, we're already going through all the rows with the for loop, base it on the criteria we want to keep finding aka "Paid Leave"
Do While ws.Range("B" & CurrentRow + 1).Value2 = "Paid Leave" 'if it's only one day, CurrentRow and amtDays remain on values where it started
CurrentRow = CurrentRow + 1
amtDays = amtDays + 1
Loop
ws2.Range("C" & Lastrow2 + 1).Value2 = amtDays
ws2.Range("E" & Lastrow2 + 1).Value2 = ws.Range("A" & CurrentRow).Value2
amtDays = 1
End If
CurrentRow = CurrentRow + 1
If CurrentRow > Lastrow Then Exit For 'no need to go further (with a while loop this isn't necessary anymore)
Next i
End Sub
If you have any further questions, feel free to ask them (properly;))
This can also be accomplished using Power Query, available in Windows Excel 2010+ and Excel 365 (Windows or Mac)
To use Power Query
Data => Get&Transform => from Table/Range
or from within sheet
Home => Advanced Editor
Applied Steps
to understand the algorithmlet
//Change Name in next line to reflect actual data source
Source = Excel.CurrentWorkbook(){[Name="Table5"]}[Content],
//Set the data types
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Date", type date}, {"Status", type text}, {"Name", type text}}),
//Group by status and Name with "GroupKind.Local" argument
#"Grouped Rows" = Table.Group(#"Changed Type", {"Status", "Name"}, {
{"Days", each Table.RowCount(_), Int64.Type},
{"Start Date", each List.Min([Date]), type nullable date},
{"End Date", each List.Max([Date]), type nullable date}},
GroupKind.Local),
//Select only "Paid Leave" in the Status column
#"Filtered Rows" = Table.SelectRows(#"Grouped Rows", each ([Status] = "Paid Leave"))
in
#"Filtered Rows"
Note: Most of this can be done in the User Interface. However, the default type
for the Date
column needs to be changed from datetime
to date
, and the GroupKind.Local
argument needs to be added manually
Editing the code and adding another approach since I have worked it out a little more before Notus_Panda's final answer.! Thanks a lot again.
Sub paid_leave()
Dim wb As Workbook
Dim sh, sh2 As Worksheet
Set wb = ActiveWorkbook
Set sh = wb.Sheets("Sheet1")
Set sh2 = wb.Sheets("Sheet2")
Currentrow = 2
i = 2
lastrow = wb.Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
amtDays = 1
Do While i <= lastrow
If wb.Sheets("Sheet1").Range("B" & i).Value2 = "Paid Leave" Then
startRow = i
endrow = i
Do While wb.Sheets("Sheet1").Range("B" & i + 1).Value2 = "Paid Leave"
endrow = endrow + 1
amtDays = amtDays + 1
i = i + 1
Loop
lastrow2 = wb.Sheets("Sheet2").Range("A" & Rows.Count).End(xlUp).Row
wb.Sheets("Sheet2").Range("A" & lastrow2 + 1).Value2 = wb.Sheets("Sheet1").Range("C" & startRow).Value2
wb.Sheets("Sheet2").Range("B" & lastrow2 + 1).Value2 = wb.Sheets("Sheet1").Range("B" & startRow).Value2
wb.Sheets("Sheet2").Range("C" & lastrow2 + 1).Value2 = amtDays
wb.Sheets("Sheet2").Range("D" & lastrow2 + 1).Value2 = wb.Sheets("Sheet1").Range("A" & startRow).Value2
wb.Sheets("Sheet2").Range("E" & lastrow2 + 1).Value2 = wb.Sheets("Sheet1").Range("A" & endrow).Value2
amtDays = 1
i = i + 1
End If
i = i + 1
Loop
End Sub
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.