根据定义日期范围的 2 个输入框,将一个选项卡中 table 中的所有数据复制到同一工作簿中的另一个选项卡中

Copying all data from a table in one tab into another tab in the same workbook based on 2 input boxes which will define a date range

我尝试了很多网站,但我真的很挣扎,因为我似乎无法理解 VBA 代码

tab1 = 来自 C8:Rx 的数据? ...数据会不断增长,所以 table 会一直变大

tab1 中的 C 列包含日期 21/05/2021

我希望能够有 2 个提示框,我可以在其中输入从 21/05/2021 到 22/05/2021 的日期

当我操作宏时,它只会从这些日期之间的 tab1 中的 table 获取数据

并将它们粘贴到 tab2 中的单元格引用 c8(table 的开头)

Option Explicit

'This subroutine prompts the user to select dates
Public Sub PromptUserForInputDates()
    
    Dim strStart As String, strEnd As String, strPromptMessage As String
    
    'Prompt the user to input the start date
    strStart = InputBox("Please enter the start date")
    
    'Validate the input string
    If Not IsDate(strStart) Then
        strPromptMessage = "Oops! It looks like your entry is not a valid " & _
                           "date. Please retry with a valid date..."
        MsgBox strPromptMessage
        Exit Sub
    End If
    
    'Prompt the user to input the end date
    strEnd = InputBox("Please enter the end date")
    
    'Validate the input string
    If Not IsDate(strStart) Then
        strPromptMessage = "Oops! It looks like your entry is not a valid " & _
                           "date. Please retry with a valid date..."
        MsgBox strPromptMessage
        Exit Sub
    End If
    
    'Call the next subroutine, which will do produce the output workbook
    Call CreateSubsetWorkbook(strStart, strEnd)
    
End Sub
'This subroutine creates the new workbook based on input from the prompts
Public Sub CreateSubsetWorkbook(StartDate As String, EndDate As String)
    
    Dim wbkOutput As Workbook
    Dim wksOutput As Worksheet, wks As Worksheet
    Dim lngLastRow As Long, lngLastCol As Long, lngDateCol As Long
    Dim rngFull As Range, rngResult As Range, rngTarget As Range
    
    'Set references up-front
    lngDateCol = 3 '<~ we know dates are in column C
    Set wbkOutput = Workbooks.Add
    
    'Loop through each worksheet
    For Each wks In ThisWorkbook.Worksheets
        With wks
        
            'Create a new worksheet in the output workbook
            Set wksOutput = wbkOutput.Sheets.Add
            wksOutput.Name = wks.Name
            
            'Create a destination range on the new worksheet that we
            'will copy our filtered data to
            Set rngTarget = wksOutput.Cells(1, 1)
        
            'Identify the data range on this sheet for the autofilter step
            'by finding the last row and the last column
            lngLastRow = .Cells.Find(What:="*", LookIn:=xlFormulas, _
                                 SearchOrder:=xlByRows, _
                                 SearchDirection:=xlPrevious).Row
            lngLastCol = .Cells.Find(What:="*", LookIn:=xlFormulas, _
                                 SearchOrder:=xlByColumns, _
                                 SearchDirection:=xlPrevious).Column
            Set rngFull = .Range(.Cells(1, 1), .Cells(lngLastRow, lngLastCol))
            
            'Apply a filter to the full range to get only rows that
            'are in between the input dates
            With rngFull
                .AutoFilter Field:=lngDateCol, _
                            Criteria1:=">=" & StartDate, _
                            Criteria2:="<=" & EndDate
                
                'Copy only the visible cells and paste to the
                'new worksheet in our output workbook
                Set rngResult = rngFull.SpecialCells(xlCellTypeVisible)
                rngResult.copy Destination:=rngTarget
            End With
            
            'Clear the autofilter safely
            .AutoFilterMode = False
            If .FilterMode = True Then
                .ShowAllData
            End If
        End With
    Next wks
    
    'Let the user know our macro has finished!
    MsgBox "Data transferred!"

End Sub

此解决方案的作用:

  • 假设您的日期在您工作Column A 中sheet。
  • 可用于替换您拥有的 CreateSubsetWorkbook 子。

您仍然可以使用 PromptUserForInputDates 然后调用此 sub 而不是 CreateSubsetWorkbook

Public Sub FillOutputRange(ByVal StartDate As Date, ByVal EndDate As Date)
    Dim SourceSheet As Worksheet
    Dim DestinationSheet As Worksheet
    Dim TargetCell As Range
    Dim LastRow As Long
    Dim StartRow As Long
    Dim EndRow As Long
    Dim RowLoopCounter As Long
    Dim EndColumn As Long
    Dim OutputDataArray As Variant
    
    With ThisWorkbook
        Set SourceSheet = .Sheets("Sheet1")         'Change this to the name of your source sheet
        Set DestinationSheet = .Sheets("Sheet2")   'Change this to the name of your destination sheet
    End With
    
    With SourceSheet
        LastRow = .Cells(Rows.Count, "A").End(xlUp).Row
        
        For Each TargetCell In .Range("A1:A" & LastRow)
            If TargetCell.Value = StartDate Then
                StartRow = TargetCell.Row
                Exit For
            End If
        Next TargetCell
        If StartRow = 0 Then MsgBox "Start Date was not found", vbOKOnly, "No Start Date": Exit Sub
        
        For RowLoopCounter = LastRow To StartRow Step -1
            If .Range("C" & RowLoopCounter).Value = EndDate Then
                EndRow = RowLoopCounter
                Exit For
            End If
        Next RowLoopCounter
        If EndRow = 0 Then MsgBox "End Date was not found", vbOKOnly, "No End Date": Exit Sub
        
        EndColumn = .Cells(EndRow, .Columns.Count).End(xlToLeft).Column
       
       OutputDataArray = .Range(.Cells(StartRow, "A"), .Cells(EndRow, EndColumn)).Value
    End With
     
    With DestinationSheet
        .Range("C8").Resize(UBound(OutputDataArray, 1), UBound(OutputDataArray, 2)).Value = OutputDataArray
    End With
    
End Sub

它是如何工作的?

本子的流程可以描述为:

  • 首先,我们设置变量以用作我们 SourceSheetDestinationSheet 的引用 - 确保将这些变量更改为工作簿的正确工作sheet 名称.
  • 然后 SourceSheet 我们找到 LastRow -
  • 然后我们使用 For Each Next Statement 遍历 Range("A1:A" & LastRow") 中的每个单元格 - 如果说 LastRow10 那么这将等同于 Range("A1:A10")
  • 在循环的每次迭代中,我们都在检查单元格的值是否与我们从 PromptUserForInputDates Sub.
  • 传递的 StartDate 参数相匹配
  • 一旦我们有了第一个匹配项,我们就将该单元格的 Row 分配给 StartRow 变量,然后退出循环,代码继续。
  • 下一个循环是 For Next Statement,它的语法略有不同。我用它来演示如何使用不同的语句。我们从范围的末尾向后循环,回到 StartRow 这样 EndRow 将从你范围内最后一次出现的 EndDate 建立。
  • 既然我们有了 StartRowEndRow,我们就知道目标数据在哪些行之间(含)。
  • EndColumn 是根据 EndRow 中数据的最后一列找到的 - 你可以根据任何行找到它,我只是选择在最后一行找到它。
  • 使用 3 个变量,StartRowEndRowEndColumn,我们可以通过将目标范围的值分配给数组变量来构建我们的 OutputDataArray。这会自动构建一个包含所有数据的二维数组。
  • 最后,使用我们的 DestinationSheet,我们现在将数组写入 sheet 中的一个范围。根据您的问题,我已将其硬编码为从 Range("C8") 开始。 Range.Resize Property 用于更改范围大小以匹配数组大小,这样数组中的数据将直接写入 sheet.

This Chip Pearson article 非常适合学习数组。

注意: 我在每个循环后添加了 If...Then 语句来捕获如果变量 StartRow and/or EndRow 未分配(意味着它们保留其默认值 0)。这通过向用户抛出一个消息框来告知未找到任何日期来处理错误。


演示

基于以下使用的日期:

StartDate = 3/6/2021

EndDate = 6/6/2021

示例源数据:

运行 子的结果:

Option Explicit

'This subroutine prompts the user to select dates
Public Sub PromptUserForInputDates()
    
    Dim strStart As String, strEnd As String, strPromptMessage As String
    
    'Prompt the user to input the start date
    strStart = InputBox("Please enter the start date")
    
    'Validate the input string
    If Not IsDate(strStart) Then
        strPromptMessage = "Oops! It looks like your entry is not a valid " & _
                           "date. Please retry with a valid date..."
        MsgBox strPromptMessage
        Exit Sub
    End If
    
    'Prompt the user to input the end date
    strEnd = InputBox("Please enter the end date")
    
    'Validate the input string
    If Not IsDate(strStart) Then
        strPromptMessage = "Oops! It looks like your entry is not a valid " & _
                           "date. Please retry with a valid date..."
        MsgBox strPromptMessage
        Exit Sub
    End If
    
    'Call the next subroutine, which will do produce the output workbook
    Call FillOutputRange(strStart, strEnd)
    
End Sub

Public Sub FillOutputRange(ByVal StartDate As Date, ByVal EndDate As Date)
    Dim SourceSheet As Worksheet
    Dim DestinationSheet As Worksheet
    Dim TargetCell As Range
    Dim LastRow As Long
    Dim StartRow As Long
    Dim EndRow As Long
    Dim RowLoopCounter As Long
    Dim EndColumn As Long
    Dim OutputDataArray As Variant
    
    With ThisWorkbook
        Set SourceSheet = .Sheets("Branches consolidated Master (4")         'Change this to the name of your source sheet
        Set DestinationSheet = .Sheets("Date Extract (5)")   'Change this to the name of your destination sheet
    End With
    
    With SourceSheet
        LastRow = .Cells(Rows.Count, "C").End(xlUp).Row
        
        For Each TargetCell In .Range("C8:C" & LastRow)
            If TargetCell.Value = StartDate Then
                StartRow = TargetCell.Row
                Exit For
            End If
        Next TargetCell
        
        For RowLoopCounter = LastRow To StartRow Step -1
            If Range("C" & RowLoopCounter).Value = EndDate Then
                EndRow = RowLoopCounter
                Exit For
            End If
        Next RowLoopCounter
        
        EndColumn = .Cells(EndRow, .Columns.Count).End(xlToLeft).Column
       
       OutputDataArray = .Range(.Cells(StartRow, "A"), .Cells(EndRow, EndColumn)).Value
    End With
     
    With DestinationSheet
        .Range("C8").Resize(UBound(OutputDataArray, 1), UBound(OutputDataArray, 2)).Value = OutputDataArray
    End With
    
End Sub

my code error

错误说应用程序定义或对象定义错误

抱歉给您带来了麻烦@samuel