【问题标题】:VBA copy-paste loopVBA 复制粘贴循环
【发布时间】:2019-05-20 22:33:15
【问题描述】:

我正在尝试遍历四个选项卡,从三个输入选项卡复制数据并将其粘贴到剩余的主选项卡中。代码应遍历主选项卡上的所有列标题,查找任何输入选项卡中是否存在相同的标题,如果存在,则将数据复制并粘贴到主选项卡的相关列中。

目前,我已将第一个输入选项卡中的所有数据放入主选项卡,但我无法从其余输入选项卡获取数据以粘贴到第一个输入选项卡的数据下方。

这是目前的代码:

Sub master_sheet_data()

Application.ScreenUpdating = False

'Variables
Dim ws1_xlRange As Range
Dim ws1_xlCell As Range
Dim ws1 As Worksheet

Dim ws2_xlRange As Range
Dim ws2_xlCell As Range
Dim ws2 As Worksheet

Dim ws3_xlRange As Range
Dim ws3_xlCell As Range
Dim ws3 As Worksheet

Dim ws4_xlRange As Range
Dim ws4_xlCell As Range
Dim ws4 As Worksheet

Dim valueToFind As String
Dim lastrow As String
Dim lastrow2 As String
Dim copy_range As String

'Assign variables to specific worksheets/ranges
'These will need to be updated if changes are made to the file.
Set ws1 = ActiveWorkbook.Worksheets("Refined event data - all")
Set ws1_xlRange = ws1.Range("A1:BJ1")

Set ws2 = Worksheets("Refined event data")
Set ws2_xlRange = ws2.Range("A1:BJ1")

Set ws3 = Worksheets("Refined MASH data")
Set ws3_xlRange = ws3.Range("A1:BJ1")

Set ws4 = Worksheets("Raw RHI data - direct referrals")
Set ws4_xlRange = ws4.Range("A1:BJ1")

'Loop through all the column headers in the all data tab
For Each ws1_xlCell In ws1_xlRange
    valueToFind = ws1_xlCell.Value
        'Loop for - Refined event data tab
        'check whether column headers match. If so, paste column from event tab to relevant column in all data tab
        For Each ws2_xlCell In ws2_xlRange
            If ws2_xlCell.Value = valueToFind Then
                ws2_xlCell.EntireColumn.Copy
                ws1_xlCell.PasteSpecial xlPasteValuesAndNumberFormats
            End If
        Next ws2_xlCell
        'Loop for - Refined ID data tab
        'check whether column headers match. If so, paste column from MASH tab to the end of relevant column in all data tab
        For Each ws3_xlCell In ws3_xlRange
            If ws3_xlCell.Value = valueToFind Then
                Range(ws3_xlCell.Address(), ws3_xlCell.End(xlDown).Address()).Copy
                lastrow = ws1.Cells(Rows.Count, ws1_xlCell.Column).End(xlUp).Row + 1
                Cells(ws1_xlCell.Column & lastrow).PasteSpecial xlPasteValuesAndNumberFormats
            End If
        Next ws3_xlCell
        'Loop for - direct date data tab
        'check whether column headers match. If so, paste column from direct J4U tab to the end of relevant column in all data tab
        For Each ws4_xlCell In ws4_xlRange
            If ws4_xlCell.Value = valueToFind Then
                Range(ws4_xlCell.Address(), ws4_xlCell.End(xlDown).Address()).Copy
                lastrow = ws1.Cells(Rows.Count, ws1_xlCell.Column).End(xlUp).Row + 1
                Cells(ws1_xlCell.Column & lastrow).PasteSpecial xlPasteValuesAndNumberFormats
            End If
        Next ws4_xlCell

Next ws1_xlCell
End Sub    

目前,这段代码:

    For Each ws3_xlCell In ws3_xlRange 
If ws3_xlCell.Value = valueToFind Then 
Range(ws3_xlCell.Address(), ws3_xlCell.End(xlDown).Address()).Copy 
lastrow = ws1.Cells(Rows.Count, ws1_xlCell.Column).End(xlUp).Row + 1
Cells(ws1_xlCell.Column & lastrow).PasteSpecial xlPasteValuesAndNumberFormats 
End If 
Next ws3_xlCell

似乎在正确的工作表上选择正确的范围并复制它。 lastrow 变量似乎在主选项卡上选择了正确的行,但未粘贴数据。我尝试命名范围并使用Cells() 而不是Range(),但似乎都不起作用。 任何关于如何粘贴数据的想法都将不胜感激。 干杯, 蚂蚁

【问题讨论】:

  • 如果不解决您手头的问题,查看您的代码会想到两件事,您可能需要考虑改进。您真的不应该遍历所有标题以查看是否存在匹配项,并且您也可以遍历您的三张工作表(当然,如果命名为 ws2-4)。如果还没有解决,午饭后我会调查你的问题:)
  • Range(ws3_xlCell.Address(), ws3_xlCell.End(xlDown).Address()).Copy Range 不适用于任何特定的工作表,因此它使用当前处于活动状态的工作表。
  • @DarrenBartrup-Cook 这会解决范围限定符问题吗? Range(ws3.ws3_xlCell.Address(), ws3.ws3_xlCell.End(xlDown).Address()).Copy 我假设通过在特定工作表中指定单元格,即使工作表未处于活动状态,这也会“锁定”范围。
  • 您还需要限定Range。目前ws4_xlCell.Address() 返回没有任何表格限定的文本地址 - 例如$D$1。所以你的范围实际上是Range("$D$1","$D$20").Copy。您也可以直接使用单个单元格,因此:WS4.RANGE(WS4_XLCELL,WS4_XLCELL.End(xlDown)).Copy

标签: excel vba loops copy-paste


【解决方案1】:

我所做的是创建一个函数来查找列标题并从该列返回数据范围。

Sub master_sheet_data()

    Application.ScreenUpdating = False

    Dim ws As Worksheet
    Dim cell As Range, source As Range, target As Range

    With ThisWorkbook.Worksheets("Raw RHI data - direct referrals")
        For Each ws In Worksheets(Array("Refined event data - all", "Refined event data", "Refined MASH data"))
            For Each cell In .Range("A1", .Cells(1, .Columns.Count).End(xlToLeft))
                Set source = getColumnDataBodyRange(ws, cell.Value)
                If Not source Is Nothing Then
                    Set target = cell.Offset(.Rows.Count - 1).End(xlUp).Offset(1)
                    source.Copy
                    target.PasteSpecial xlPasteValuesAndNumberFormats
                End If
            Next
        Next
    End With
    Application.CutCopyMode = False
    Application.ScreenUpdating = True
End Sub

Function getColumnDataBodyRange(ws As Worksheet, ColumnHeader As Variant) As Range
    Dim cell As Range
    With ws
        Set cell = .Rows(1).Find(What:=ColumnHeader, After:=.Range("A1"))
        If Not cell Is Nothing Then
            Set getColumnDataBodyRange = .Range(cell.Offset(1), cell.Offset(.Rows.Count - 1).End(xlUp))
        End If
    End With
End Function

【讨论】:

  • 您可能不需要Application.ScreenUpdating = False,或者至少需要在最后将其转回True。否则和我想的差不多。 (+1)。
  • Application.ScreenUpdating 肯定会加快代码速度。我没有重新打开它,因为您不再需要。我继续更新我的代码以重新打开它以实现向后兼容性。谢谢@DarrenBartrup-Cook
  • 不知道您不再需要重新打开它。什么时候发生的?我对Screenupdating 有两种看法。这取决于您要更改的工作表是否是活动工作表 - 我在使用活动工作表的 this 页面上运行了代码 - 更新屏幕占用了 5.210937,而不是更新屏幕占用了 0.46875 显然要快得多。当我将它从 Activesheet 更改为没有并留下屏幕更新时,它花了 0.484375 所以只慢了一点。
  • @DarrenBartrup-Cook 很明显Screenupdating 只有在对ActiveSheet 进行更改时才会有所作为。 IMO,在写入工作表时,您仍然应该使用它,除非您只是转储一个值数组。我的理由是,无论哪个工作表处于活动状态,我都希望我的代码运行。谢谢你的信息,兄弟。
  • 不错!这更有意义:)
猜你喜欢
  • 2019-12-27
  • 2015-12-02
  • 1970-01-01
  • 2019-01-23
  • 2020-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-18
相关资源
最近更新 更多