繁体   English   中英

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

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

我在 excel 电子表格中有以下数据

初始数据

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

结束状态数据

因此,对于每个员工,计算额外行中连续带薪休假的天数以及开始和结束日期(开始第一天和结束连续休假的最后一天)。

我还没有想出解决这个问题的方法。 我在 VBA 方面的经验最少,到目前为止,据我所知,这个逻辑似乎非常复杂。 如果有人能提供帮助,我将不胜感激。

评论时间太长了,所以这里可以帮助你:我们尽量不在没有 OP 的情况下为别人做东西,甚至尝试编写任何代码。 要进入 VBA,请尝试使用宏阅读器,然后阅读 Excel VBA 中的如何避免使用 Select ,也许从https 开始://www.simplilearn.com/tutorials/excel-tutorial so/excel-tutorial你有点明白一切是做什么/是为了什么。 至于从头到尾的逻辑state:

  • 声明并设置您的工作簿和工作表
  • Currentrow = 1(或者你想从哪里开始)
  • go 通过带有 for 循环的 B 列从 1 到 Lastrow(对于 i = Currentrow 到 Lastrow)
  • if Range("B" & i).Value2 = "带薪休假"
  • 将 i 填充到不同的变量中以存储您的 startRow(如果下班多日)
  • 相同,但在您的 endrow 变量中(稍后会派上用场)
  • 然后使用 while 循环检查下一行是否也有带薪休假,并相应地调整你的 endrow
  • 在同一个 while 循环中,将 Currentrow 调整为 Currentrow + 1(对于每一行,下一个是带薪休假,您需要增加 for 循环中的步长)
  • amtDays = amtDays+1(while 循环结束)
  • 仍然在那个 If 语句中顺便说一句:
  • 获取不同工作表的最后一行 (lastrow2),然后在变量的帮助下填写值,即 Start Date 列将获取 wbOther.wsOther.Range("D" & lastrow2 + 1).Value2 = wbStart.wsStart.Range ("A" & startRow).Value2
  • amtDays = 1(如果结束)
  • 按日期排序(您可以在最后的另一张表中执行此操作)

然后,如果您在尝试所有这些之后仍然遇到困难,请回来,我们很乐意提供帮助:)

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

如果您有任何其他问题,请随时问他们(适当地;))

这也可以使用 Power Query 完成,在 Windows Excel 2010+ 和 Excel 365(Windows 或 Mac)中可用

使用 Power Query

  • Select 数据表中的某个单元格
  • Data => Get&Transform => from Table/Rangefrom within sheet
  • 当 PQ 编辑器打开时: Home => Advanced Editor
  • 记下第 2 行中的表名称
  • 粘贴下面的 M 代码代替您看到的内容
  • 将第 2 行中的表名称更改回最初生成的名称。
  • 阅读评论并探索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"

在此处输入图像描述

注意:其中大部分可以在用户界面中完成。 但是,需要将Date列的默认typedatetime更改为date ,并且需要手动添加GroupKind.Local参数

编辑代码并添加另一种方法,因为在 Notus_Panda 的最终答案之前我已经解决了更多问题。! 再次感谢。

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