Excel VBA Копировать Вставить данные слишком медленно - PullRequest
0 голосов
/ 16 марта 2020

У меня есть следующий код, который захватывает данные из многих рабочих листов в моей рабочей книге и выгружает их в новый рабочий лист с именем «Export_Sheet».

Так как код основан на методе Copy \ Paste, он занимает вечность, и я ищите заменить это чем-то намного более быстрым.

Есть какие-нибудь подсказки? Я не ищу решения для этого, скорее просто направляю в правильном направлении, так как сам не знаю более быстрых процессов, но уверен, что они существуют.

Private Sub CommandButton3_Click()
Application.ScreenUpdating = False
Worksheets.Add(After:=Worksheets(1)).Name = "Export_Sheet"

Dim Ws As Worksheet

For Each Ws In ThisWorkbook.Worksheets
If Ws.Name <> "Contents Page" And Ws.Name <> "Completed" And Ws.Name <> "VBA_Data" And Ws.Name <> "Front Team Project List" And Ws.Name <> "Mid Team Project List" And Ws.Name <> "Rear Team Project List" And Ws.Name <> "Acronyms" Then

LastRow = Ws.Cells(Rows.Count, 1).End(xlUp).Row

For i = 6 To LastRow

Ws.Cells(i, 9).EntireRow.Copy
Sheets("Export_Sheet").Range("A" & Rows.Count).End(xlUp).Offset(1).Select
Selection.PasteSpecial xlPasteValues
Sheets("Export_Sheet").Range("j" & Rows.Count).End(xlUp).Value = Ws.Name

If Ws.Range("J1").Value = "Front Team" Then
Sheets("Export_Sheet").Range("k" & Rows.Count).End(xlUp).Offset(1).Value = "Front Team"
End If

If Ws.Range("J1").Value = "Mid Team" Then
Sheets("Export_Sheet").Range("k" & Rows.Count).End(xlUp).Offset(1).Value = "Mid Team"
End If

If Ws.Range("J1").Value = "Rear Team" Then
Sheets("Export_Sheet").Range("k" & Rows.Count).End(xlUp).Offset(1).Value = "Rear Team"
End If

Next i

End If
Next
End Sub

Ответы [ 4 ]

0 голосов
/ 16 марта 2020

Не проверено, поскольку у меня нет вашей рабочей книги, но это должно быть на несколько порядков быстрее ...

Private Sub CommandButton3_Click()
    Dim Ws As Worksheet
    Application.ScreenUpdating = False
    Worksheets.Add(After:=Worksheets(1)).Name = "Export_Sheet"

    For Each Ws In ThisWorkbook.Worksheets
        With Ws
            If .Name <> "Contents Page" And .Name <> "Completed" And .Name <> "VBA_Data" And .Name <> "Front Team Project List" And .Name <> "Mid Team Project List" And .Name <> "Rear Team Project List" And .Name <> "Acronyms" Then
                For i = 6 To .Cells(Rows.Count, 1).End(xlUp).Row
                    With Sheets("Export_Sheet").Range("A" & Rows.Count).End(xlUp).Offset(1)
                        .Value = Ws.Cells(i, 9).EntireRow.Value
                        .Offset(, 9).Value = Ws.Name
                        Select Case Ws.Range("J1").Value
                            Case "Front Team", "Mid Team", "Rear Team": .Offset(, 9).Value = Ws.Range("J1").Value
                        End Select
                    End With
                Next
            End If
        End With
    Next
End Sub
0 голосов
/ 16 марта 2020

Хорошо. Вот мой удар для прямой передачи вместо использования буфера обмена. Могут быть и более эффективные способы.

Свойство UsedRange рабочего листа - это все, начиная с Range ("A1") и заканчивая там, где вас ждут Ctrl + End. Там могут быть пустые ячейки, но там, где Excel считает конец «используемого диапазона». Это необходимо, чтобы ограничить диапазон .EntireRow, или он может простираться по всему листу до столбца # 16,384, максимальный для количества столбцов.

Мое понимание того, что вы пытаетесь скопировать, немного шатко, но это l oop в середине, что делает это. Сначала он использует Intersect (), чтобы пересечь .UsedRange со строкой, в которой вы хотите работать. Затем он пересчитывает диапазоны источника и назначения по одной ячейке за раз и копирует значение из одной в другую.

Private Sub CommandButton3_Click()
    Application.ScreenUpdating = False
    Worksheets.Add(After:=Worksheets(1)).Name = "Export_Sheet"

    Dim Ws      As Worksheet
    Dim ur      As Excel.range
    Dim srcCell As Excel.range
    Dim srcRng  As Excel.range
    Dim srcCnt  As Long
    Dim xferCnt As Long
    Dim topCell As Excel.range

    For Each Ws In ThisWorkbook.Worksheets
        Set ur = Ws.UsedRange 'This is usually A1 to where Ctrl+End sends you.
        If Ws.Name <> "Contents Page" And Ws.Name <> "Completed" And Ws.Name <> "VBA_Data" And Ws.Name <> "Front Team Project List" And Ws.Name <> "Mid Team Project List" And Ws.Name <> "Rear Team Project List" And Ws.Name <> "Acronyms" Then
            LastRow = Ws.Cells(rows.Count, 1).End(xlUp).row
            For i = 6 To LastRow
                Set srcRng = Intersect(ur, Ws.Cells(i, 9).EntireRow)    'Only get the used part of the row.
                srcCnt = dataRng.Cells.Count                            'Count of cells in source.
                For xferCnt = 0 To srcCnt - 1
                    'Now you basically need something like this,
                    'Get the top cell as a reference point.
                    Set topCell = Sheets("Export_Sheet").range("A" & rows.Count).End(xlUp).Offset(1)
                    'Then transfer each cell one at a time.
                    topCell.Offset(0, xferCnt).Value = srcRng.Cells(xferCnt).Value
                    Sheets("Export_Sheet").range("j" & rows.Count).End(xlUp).Value = Ws.Name
                Next
                If Ws.range("J1").Value = "Front Team" Then
                    Sheets("Export_Sheet").range("k" & rows.Count).End(xlUp).Offset(1).Value = "Front Team"
                End If
                If Ws.range("J1").Value = "Mid Team" Then
                    Sheets("Export_Sheet").range("k" & rows.Count).End(xlUp).Offset(1).Value = "Mid Team"
                End If
                If Ws.range("J1").Value = "Rear Team" Then
                    Sheets("Export_Sheet").range("k" & rows.Count).End(xlUp).Offset(1).Value = "Rear Team"
                End If
            Next i
        End If
    Next
End Sub
0 голосов
/ 16 марта 2020

Это не относится к вашему указанному c коду; он просто демонстрирует альтернативный подход.

Этот код:

Sub CopyPaste()
    Sheets("Sheet1").Range("A1:Z100").Copy
    Sheets("Sheet2").Range("A1").PasteSpecial (xlPasteValues)
End Sub

может показаться довольно быстрым, если он не выполняется в больших циклах. Если все, что у вас есть, это данные (без формул) , то:

Sub Value2Value()
    Sheets("Sheet2").Range("A1:Z100").Value = Sheets("Sheet1").Range("A1:Z100").Value
End Sub

быстрее. Если в блоке есть формулы, то:

Sub Form2Form()
    Sheets("Sheet2").Range("A1:Z100").Formula = Sheets("Sheet1").Range("A1:Z100").Formula
End Sub

скопирует как формулы, так и данные.

Недостаток быстрых копий заключается в том, что форматирование может не копироваться вместе со значениями.

0 голосов
/ 16 марта 2020

Попробуйте этот код, пожалуйста. Чего я не понял, так это того, как справиться с «Front Team», «Mid Team» и «Rear Team». Должны ли они быть написаны на каждой строке? Если да, это можно сделать, но массив должен заполняться строка за строкой, теряя некоторое время. Я не мог понять, почему, и код помещает их по одному разу в конце каждого диапазона листа ... Пожалуйста, уточните вашу потребность с этой точки view.

Private Sub CommandButton3_Click()
 Dim Ws As Worksheet, lastRow As Long, lastCol As Long
 Dim shExp As Worksheet, arrTransf As Variant

  Set shExp = Worksheets.Add(After:=Worksheets(1))
  shExp.Name = "Export_Sheet"

 For Each Ws In ThisWorkbook.Worksheets
  If Ws.Name <> "Contents Page" And Ws.Name <> "Completed" And _
            Ws.Name <> "VBA_Data" And Ws.Name <> "Front Team Project List" And _
            Ws.Name <> "Mid Team Project List" And Ws.Name <> _
                      "Rear Team Project List" And Ws.Name <> "Acronyms" Then
    lastRow = Ws.Cells(Rows.Count, 1).End(xlUp).Row

        lastCol = Ws.UsedRange.Columns.Count
        arrTransf = Ws.Range(Ws.Cells(6, 1), Ws.Cells(lastRow, lastCol)).value
        shExp.Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(UBound(arrTransf, 1), _
                                            UBound(arrTransf, 2)).value = arrTransf
        'this line replaces the last value in the column J:J, but so was the original code
        shExp.Range("j" & Rows.Count).End(xlUp).value = Ws.Name

        If Ws.Range("J1").value = "Front Team" Then _
            shExp.Range("k" & Rows.Count).End(xlUp).Offset(1).value = "Front Team"

        If Ws.Range("J1").value = "Mid Team" Then _
            shExp.Range("k" & Rows.Count).End(xlUp).Offset(1).value = "Mid Team"

        If Ws.Range("J1").value = "Rear Team" Then _
            shExp.Range("k" & Rows.Count).End(xlUp).Offset(1).value = "Rear Team"
  End If
 Next
End Sub

Edited: второй код, который касается вставки другой строки после каждого сохранения данных. Пожалуйста, проверьте это и подтвердите, что это то, что вы хотели. Особенно, что касается позиции названия листа ...

Private Sub CommandButton3_Click()
 Dim Ws As Worksheet, lastRow As Long, lastCol As Long, k As Long, i As Long
 Dim shExp As Worksheet, arrTransf As Variant, arrFin As Variant, m As Long

  Set shExp = Worksheets.Add(After:=Worksheets(1))
  shExp.Name = "Export_Sheet"

 For Each Ws In ThisWorkbook.Worksheets
      If Ws.Name <> "Contents Page" And Ws.Name <> "Completed" And _
            Ws.Name <> "VBA_Data" And Ws.Name <> "Front Team Project List" And _
            Ws.Name <> "Mid Team Project List" And Ws.Name <> _
                      "Rear Team Project List" And Ws.Name <> "Acronyms" Then

        lastRow = Ws.Cells(Rows.Count, 1).End(xlUp).Row

        lastCol = Ws.UsedRange.Columns.Count
        arrTransf = Ws.Range(Ws.Cells(6, 1), Ws.Cells(lastRow, lastCol)).value

        ReDim arrFin(1 To UBound(arrTransf, 2), 1 To UBound(arrTransf, 1) * 4)
        For i = 1 To UBound(arrTransf, 1)
            For m = 1 To UBound(arrTransf, 2)
                arrFin(m, i + IIf(m > 11, k - 1, k)) = arrTransf(i, m)
                If m = 10 Then arrFin(10, i + k) = Ws.Name
                'If you would need the sheet name on the same row with "xxx Team, replace the above line with the next one. In fact uncomment it and delete the above one:
                'If m = 10 Then arrFin(10, i + k + 1) = Ws.Name
                If m = 11 Then
                    If Ws.Range("J1").value = "Front Team" Then
                        arrFin(11, i + k + 1) = "Front Team": k = k + 1
                    ElseIf Ws.Range("J1").value = "Mid Team" Then
                        arrFin(11, i + k + 1) = "Mid Team": k = k + 1
                    ElseIf Ws.Range("J1").value = "Rear Team" Then
                        arrFin(11, i + k + 1) = "Rear Team": k = k + 1
                    End If
                End If
            Next m
        Next i
        ReDim Preserve arrFin(1 To UBound(arrTransf, 2), i + k - 2)
        shExp.Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(UBound(arrFin, 2), _
                        UBound(arrFin, 1)).value = WorksheetFunction.Transpose(arrFin)
     End If
 Next
End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...