Excel - 横越和向下匹配

时间:2017-11-30 02:40:29

标签: excel vba excel-vba

我有一张包含两张纸的工作簿,第一张看起来像这样:

 --------------------------------------------------------
 Last Name | First Name | 1-Jan | 2-Jan | 3-Jan | 4-Jan | (continues on like this)
 --------------------------------------------------------
 SMITH     | John       |    1  |    1  |       |       |
 --------------------------------------------------------
 BOND      | James      |       |       |    1  |    1  |
 --------------------------------------------------------

第二张

 --------------------------------------------------------
                        |   January     | February      | (continues on etc)  
 --------------------------------------------------------
 Last Name | First Name | From  | To    | From  | To    | 
 --------------------------------------------------------
 SMITH     | John       |1/1/18 | 2/2/18|       |       |
 --------------------------------------------------------
 BOND      | James      |3/1/18 |4/1/18 |       |       |
 --------------------------------------------------------

这是一张请假表,基本上用户在他们休假的那天在第一张纸上输入'1'。然后在第二张表中自动更新,以反映每个月的休假日期。

因此,在第一个示例中,用户在1月1日和1月1日输入1,这将从1/1/18到2/1/18更新第二张表并留下该员工的假期。

到目前为止,我成功地能够检测到1何时进入它抓取名称和日期详细信息,我一直在使用msgbox来验证我是否获得了正确的数据。

我遇到的问题是我能得到的,我无法找到如何搜索第二张表来查找日期并相应更新。

 Private Sub Worksheet_Change(ByVal Target As Range)
     Dim KeyCells As Range
     ' The variable KeyCells contains the cells that will
     ' cause an alert when they are changed.
     Set KeyCells = Range("D6:OI53")
     If Not Application.Intersect(KeyCells, Range(Target.Address)) _
         Is Nothing Then
         ' If cell changed, do the below '
         ' Get name '
         Dim lastName As String
         Dim firstName As String
         lastName = ActiveSheet.Cells(Target.Cells.Row, 1).Value
         firstName = ActiveSheet.Cells(Target.Cells.Row, 2).Value
    'Get date '
    Dim leaveDate As String
    leaveDate = ActiveSheet.Cells(5, Target.Cells.Column).Value
    ' Test lastname, firstname, date '
    UpdateMonthlyLeave lastName, firstName, leaveDate
     End If
 End Sub

 Sub UpdateMonthlyLeave(lastName As String, firstName As String, leaveDate As String)
    MsgBox lastName & " " & firstName & " " & leaveDate
    ' Find employee on monthly leave sheet '

 End Sub

1 个答案:

答案 0 :(得分:1)

此UDF将返回开始或结束日期的列表。只需让你为表2中的列选择换行文本。我认为Excel的一个优点是只有在指定的范围发生变化时才会使用公式更新单元格。

也许代码可以进一步简化,但不幸的是你必须输入sheet2中每个单元格的公式。

Option Explicit
' ShowStartMonth: True If we need to return the start date of the holidays
' MonthRange: The WHOLE Column range of the Month
' RowRange: The Range of the person's row but only the holiday columns, not the name columns
' MonthNameRow: The entire row of where the Month name is
Public Function GetHoliday(ShowStartMonth As Boolean, iMonth As Integer, RowRange As Range, MonthNameRow As Range) As String

    Dim MonthRange As Range
    Set MonthRange = GetMonthRange(iMonth, MonthNameRow)

    'Init variables
    '   Get the cells for the current month
    Dim rRow As Range
    Set rRow = Intersect(RowRange, RowRange.Worksheet.UsedRange, MonthRange)


    Dim IsCurrentCellHoliday As Boolean
    Dim IsLastCellHoliday As Boolean
    Dim IsStartHolidayContinuation As Boolean

    ' If First Day of month is a holiday and last day of last month is a holiday then
    ' Holiday is continuation
    IsStartHolidayContinuation = (rRow.Cells(1).Value = 1) And (rRow.Cells(1).Offset(0, -1).Value = 1)
    IsLastCellHoliday = (rRow.Cells(1).Value = 1)

    ' These will hold the dates for start or end of a holiday
    Dim StartDays() As String
    Dim EndDays() As String
    ReDim StartDays(0 To 255)
    ReDim EndDays(0 To 255)

    Dim SDIndex As Integer  ' Index of the start day array
    Dim EDIndex As Integer  ' Index of the end day array

    ' If Start of month is start of a new holiday then set it
    If (IsLastCellHoliday And Not IsStartHolidayContinuation) Then StartDays(0) = GetMonthName(rRow.Cells(1), MonthNameRow)

    ' If start of month is a holiday then set index to the second "StartHoliday" line
    SDIndex = IIf(IsStartHolidayContinuation Or IsLastCellHoliday, 1, 0) ' Keep first row Empty if start of month is holiday
    EDIndex = 0


    ' Loop through all cells in the month for the person
    Dim i As Integer
    For i = SDIndex + 1 To rRow.Columns.Count
        Dim rCell As Range
        Set rCell = rRow.Cells(i)

        IsCurrentCellHoliday = rCell.Value = 1  'Check if current cell is a holiday

        ' If the current cell is different to the last cell then we need to do something
        If IsCurrentCellHoliday <> IsLastCellHoliday Then
            If IsCurrentCellHoliday Then

                StartDays(SDIndex) = GetMonthName(rCell, MonthNameRow)
                SDIndex = SDIndex + 1

                ' Check if the first day of the next month is a holiday, if not then today is the last day
                If rCell.Column = MonthRange.Columns(MonthRange.Columns.Count).Column And rCell.Offset(0, 1).Value <> 1 Then
                    EndDays(EDIndex) = GetMonthName(rRow.Cells(i), MonthNameRow)
                    EDIndex = EDIndex + 1
                End If
            Else
                EndDays(EDIndex) = GetMonthName(rRow.Cells(i - 1), MonthNameRow)
                EDIndex = EDIndex + 1
            End If
        End If
        IsLastCellHoliday = IsCurrentCellHoliday
    Next

    Dim ReturnStrings() As String
    Dim ReturnIndex As Integer

    If (ShowStartMonth) Then
        ReturnStrings = StartDays
        ReturnIndex = SDIndex
    Else
        ReturnStrings = EndDays
        ReturnIndex = EDIndex
    End If

    Dim returnString As String
    returnString = IIf(Len(ReturnStrings(0)) = 0, " - ", ReturnStrings(0))

    Dim j As Integer
    For j = LBound(ReturnStrings) + 1 To ReturnIndex - 1
        returnString = returnString & vbNewLine & ReturnStrings(j)
    Next

    GetHoliday = returnString
End Function

Private Function GetMonthName(cell As Range, MonthRow As Range) As String
    Dim rMonth As Range
    Set rMonth = Intersect(cell.EntireColumn, MonthRow.EntireRow)
End Function

Public Function GetMonthRange(iMonth As Integer, MonthNameRow As Range) As Range

    Set MonthNameRow = Intersect(MonthNameRow.EntireRow, MonthNameRow.Worksheet.UsedRange)

    Dim startCell As Range
    Dim endCell As Range

    Dim rCell As Range
    For Each rCell In MonthNameRow.Cells
        If IsDate(rCell.Value) Then
            If month(CDate(rCell.Value)) = iMonth Then
                If startCell Is Nothing Then
                 Set startCell = rCell
                ElseIf rCell.Column < startCell.Column Then
                    Set startCell = rCell
                End If

                If endCell Is Nothing Then
                 Set endCell = rCell
                ElseIf rCell.Column > endCell.Column Then
                    Set endCell = rCell
                End If
            End If
        End If
    Next

    Set GetMonthRange = Range(startCell.Address & ":" & endCell.Address).EntireColumn
    Dim sAddress As String
    sAddress = GetMonthRange.Address
End Function