简体   繁体   English

使用 Excel VBA 计算列中连续值的 COUNT

[英]Calculate COUNT of consecutive values in a column with Excel VBA

I have the below data in an excel spreadsheet我在 excel 电子表格中有以下数据

初始数据

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:我想循环浏览 B 列并为每个员工捕获连续的带薪休假并生成另一个聚合表,如下所示:

结束状态数据

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.我在 VBA 方面的经验最少,到目前为止,据我所知,这个逻辑似乎非常复杂。 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.评论时间太长了,所以这里可以帮助你:我们尽量不在没有 OP 的情况下为别人做东西,甚至尝试编写任何代码。 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.要进入 VBA,请尝试使用宏阅读器,然后阅读 Excel VBA 中的如何避免使用 Select ,也许从https 开始://www.simplilearn.com/tutorials/excel-tutorial so/excel-tutorial你有点明白一切是做什么/是为了什么。 As for logic getting from initial to end state:至于从头到尾的逻辑state:

  • declare and set your workbook(s) and worksheets声明并设置您的工作簿和工作表
  • Currentrow = 1 (or wherever you want to start from) Currentrow = 1(或者你想从哪里开始)
  • go from 1 to Lastrow through your B-column with for-loop (For i = Currentrow to Lastrow) go 通过带有 for 循环的 B 列从 1 到 Lastrow(对于 i = Currentrow 到 Lastrow)
  • if Range("B" & i).Value2 = "Paid Leave" if Range("B" & i).Value2 = "带薪休假"
  • Stuff i in a different variable to store your startRow (if multiple days off work)将 i 填充到不同的变量中以存储您的 startRow(如果下班多日)
  • Same but in your endrow variable (this will come in handy later)相同,但在您的 endrow 变量中(稍后会派上用场)
  • Then use a while loop to check if the next row has Paid leave as well and adjust your endrow accordingly然后使用 while 循环检查下一行是否也有带薪休假,并相应地调整你的 endrow
  • In the same while loop adjust Currentrow to Currentrow + 1 (for each row the next is paid leave, you need to increase your step in the for loop)在同一个 while 循环中,将 Currentrow 调整为 Currentrow + 1(对于每一行,下一个是带薪休假,您需要增加 for 循环中的步长)
  • amtDays = amtDays+1 (end of while loop) amtDays = amtDays+1(while 循环结束)
  • still in that If statement btw:仍然在那个 If 语句中顺便说一句:
  • get your lastrow of different sheet (lastrow2) and then fill out the values with the help of your variables, ie Start Date column would get wbOther.wsOther.Range("D" & lastrow2 + 1).Value2 = wbStart.wsStart.Range("A" & startRow).Value2获取不同工作表的最后一行 (lastrow2),然后在变量的帮助下填写值,即 Start Date 列将获取 wbOther.wsOther.Range("D" & lastrow2 + 1).Value2 = wbStart.wsStart.Range ("A" & startRow).Value2
  • amtDays = 1 (end of if) amtDays = 1(如果结束)
  • sort on date (you can do this in your other sheet at the end)按日期排序(您可以在最后的另一张表中执行此操作)

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.编辑在看到你实际尝试了一些东西之后,这是我的修订版本(希望)可以理解的评论,我以前使用过类似的代码,我不知道为什么我选择了 for-loop 而不是 while但在这种情况下都可以。

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)这也可以使用 Power Query 完成,在 Windows Excel 2010+ 和 Excel 365(Windows 或 Mac)中可用

To use Power Query使用 Power Query

  • Select some cell in your Data Table Select 数据表中的某个单元格
  • Data => Get&Transform => from Table/Range or from within sheet Data => Get&Transform => from Table/Rangefrom within sheet
  • When the PQ Editor opens: Home => Advanced Editor当 PQ 编辑器打开时: Home => Advanced Editor
  • Make note of the Table Name in Line 2记下第 2 行中的表名称
  • Paste the M Code below in place of what you see粘贴下面的 M 代码代替您看到的内容
  • Change the Table name in line 2 back to what was generated originally.将第 2 行中的表名称更改回最初生成的名称。
  • Read the comments and explore the Applied Steps to understand the algorithm阅读评论并探索Applied Steps以了解算法
let

//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但是,需要将Date列的默认typedatetime更改为date ,并且需要手动添加GroupKind.Local参数

Editing the code and adding another approach since I have worked it out a little more before Notus_Panda's final answer.!编辑代码并添加另一种方法,因为在 Notus_Panda 的最终答案之前我已经解决了更多问题。! 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM