Скопируйте и вставьте строку с одного листа на другой в Excel

Я пытаюсь настроить систему архивации, при которой, когда пользователь выбирает «Да» в раскрывающемся списке столбцов и нажимает кнопку «Архивировать», все записи, выбранные для архивирования, будут перемещены на другой лист. Однако проблема, с которой я сталкиваюсь, заключается в том, что каждый раз, когда запись архивируется, она просто перезаписывает предыдущую запись, которая была заархивирована, поэтому на листе архива всегда есть только 1 строка. Это код, с которым я сейчас работаю

    Sub Archive_Yes()
    Dim MatchRow As Long, FirstRow As Long, LastRow As Long
    Dim Destination As Range

    Dim ws As Worksheet
    Dim i As Long
    Set ws = Sheets("Sales Order Log")

    FirstRow = 14
    LastRow = ws.Cells(ws.Rows.Count, "AA").End(xlUp).Row
    i = FirstRow
    
    Do While i <= LastRow
       If ws.Range("AA" & i).Value = "Yes" Then
           MatchRow = ws.Range("Z" & i).Row
 
           With Sheets("Archive")
             Set Destination = .Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0)
          End With

            ws.Range("A" & MatchRow & ":Z" & MatchRow).Copy Destination

            ws.Rows(MatchRow).Delete Shift = xlUp

            LastRow = LastRow - 1
        Else
   
          i = i + 1
        End If
    Loop
   
End Sub

Любое руководство будет очень признательно. Спасибо

Что вы ожидаете от линейки MatchRow = ws.Range("Z" & i).Row? Так будет всегда i...

FaneDuru 11.05.2022 11:01

Я надеялся, что это позволит вырезать и вставить всю информацию до столбца Z в любые строки, в которых есть «Да» в столбце архива, который имеет значение AA.

Strexxin 11.05.2022 11:07

Вы хотите вставить в "AA:AA" или в "A:A"? Ваш код устанавливает (правильно) последнюю ячейку в столбце "А:А"... Я имею в виду Destination. Много ли таких строк нужно скопировать? Если это так, то более быстрым способом было бы поместить их в диапазон Union и скопировать их все сразу в конец кода. Если такой диапазон Union тоже будет огромным, его следует скопировать в несколько шагов. Могу показать как, если интересно... Но сначала уточните вопрос столбца куда вставлять.

FaneDuru 11.05.2022 11:08

Строки, которые необходимо вырезать, расположены от A: Z и должны быть взяты из листа под названием «Журнал заказов на продажу» и вставлены в лист под названием «Архив». Вероятно, в год архивируется около 200 строк.

Strexxin 11.05.2022 11:15

Поэтому их нужно вставить в столбец «А:А» (листа «Архив»). Правильно ли это понимание?

FaneDuru 11.05.2022 11:17

Начиная со столбца A yes и до Z. AA не нужно вставлять, так как именно здесь принимается решение об архивации записи, и он просто содержит раскрывающийся список, содержащий «Да».

Strexxin 11.05.2022 11:20
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
2
6
41
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Переместите строки критериев, используя AutoFilter

Sub Archive_Yes()
    
    Const sName As String = "Sales Order Log"
    Const sHeaderRowAddress As String = "A13:AA13"
    Const CriteriaColumn As Long = 27
    Const CriteriaString As String = "Yes"
    
    Const dName As String = "Archive"
    Const dFirstCellAddress As String = "A2"
    
    Dim sws As Worksheet: Set sws = ThisWorkbook.Worksheets(sName)
    If sws.FilterMode Then sws.ShowAllData
    
    Dim srCount As Long
    Dim srg As Range
    With sws.Range(sHeaderRowAddress)
        Dim slRow As Long
        slRow = sws.Cells(sws.Rows.Count, CriteriaColumn).End(xlUp).Row
        srCount = slRow - .Row + 1
        If srCount < 2 Then Exit Sub ' no data or only headers
        Set srg = .Resize(srCount)
    End With
    Dim scCount As Long: scCount = srg.Columns.Count
    Dim sdrg As Range ' exclude headers and last column
    Set sdrg = srg.Resize(srCount - 1, scCount - 1).Offset(1)
          
    srg.AutoFilter CriteriaColumn, CriteriaString
          
    Dim svrg As Range
    On Error Resume Next
        Set svrg = sdrg.SpecialCells(xlCellTypeVisible)
    On Error GoTo 0
    sws.AutoFilterMode = False
    
    If svrg Is Nothing Then
        MsgBox "No filtered rows.", vbExclamation
        Exit Sub
    End If
        
    Dim dws As Worksheet: Set dws = ThisWorkbook.Worksheets(dName)
    
    Dim dfCell As Range
    
    With dws.Range(dFirstCellAddress)
        
        Dim dlRow As Long
        dlRow = dws.Cells(dws.Rows.Count, .Column).End(xlUp).Row
        
        If dlRow < .Row Then
            Set dfCell = .Cells
        Else
            Set dfCell = dws.Cells(dlRow + 1, .Column)
        End If
    
    End With
    
    svrg.Copy dfCell
    svrg.EntireRow.Delete Shift:=xlShiftUp
     
    MsgBox "Data archived.", vbInformation
   
End Sub

Пожалуйста, попробуйте следующий адаптированный код:

Sub Archive_Yes()
    Dim FirstRow As Long, LastRow As Long, Destination As Range, rngDel As Range

    Dim ws As Worksheet, i As Long
    Set ws = Sheets("Sales Order Log")

    FirstRow = 14
    LastRow = ws.cells(ws.rows.count, "AA").End(xlUp).row
    
    For i = FirstRow To LastRow
       If ws.Range("AA" & i).value = "Yes" Then
            AddRange rngDel, ws.Range("A" & i & ":Z" & i)
        End If
    Next i
    Dim wsA As Worksheet, lastRowA As Long
    Set wsA = Sheets("Archive")
    lastRowA = wsA.Range("A" & wsA.rows.count).End(xlUp).row + 1

    If Not rngDel Is Nothing Then
         Debug.Print rngDel.Address, lastRowA: Stop
        Application.ScreenUpdating = False: Application.EnableEvents = False
        Application.Calculation = xlCalculationManual
          rngDel.Copy wsA.Range("A" & lastRowA)
          rngDel.EntireRow.Delete
        Application.ScreenUpdating = True: Application.EnableEvents = True
        Application.Calculation = xlCalculationAutomatic
    End If
End Sub

Sub AddRange(rngU As Range, rngAdd As Range)
    If rngU Is Nothing Then
        Set rngU = rngAdd
    Else
        Set rngU = Application.Union(rngU, rngAdd)
    End If
End Sub

Это должно быть очень быстро... Пожалуйста, отправьте отзыв после тестирования.

Спасибо за этот код. Я не уверен, что у меня есть какие-то другие настройки, но этот код очень похож на мой, у меня было две тестовые записи 11111 и 22222. Когда я заархивировал 11111, все было в порядке, когда я заархивировал 22222, он просто вставил 11111, а не под ним, поэтому архив показывает только одну архивную запись

Strexxin 11.05.2022 11:50

@Strexxin Я не уверен, что смогу тебя достать ... Что означает «11111 и 22222»? Он вставил только одну строку? Это что значит "одна архивная запись"? Вы должны знать, что «да» и «да» или «да» отличаются от VBA тем, как вы пытаетесь его использовать... Если это проблема, я могу быстро адаптировать код. Можете ли вы поделиться макетом такой рабочей тетради, чтобы провести на ней несколько тестов?

FaneDuru 11.05.2022 12:05

Тестовых записей было две, я для простоты назвал их 11111 и 22222. Что я хочу для архива, так это чтобы каждая запись была вставлена ​​​​под последней, поскольку она архивируется, поэтому все данные сохраняются. Однако в настоящее время происходит то, что каждая запись архивируется, она вставляется поверх предыдущей, что означает потерю данных.

Strexxin 11.05.2022 12:07

@Strexxin Боюсь, это невозможно. Я тестировал код... Можете ли вы поделиться чем-нибудь красноречивым?

FaneDuru 11.05.2022 12:08

Значит, нельзя написать код, который просто находит следующую пустую строку и вставляет в нее запись?

Strexxin 11.05.2022 12:09

@Strexxin Конечно, это можно сделать разными способами! Но установка последней пустой ячейки в «A:A» была правильной в вашем исходном коде, и я пытался адаптировать только остальную часть.

FaneDuru 11.05.2022 12:12

Это все, что мне нужно, чтобы код распознал последнюю строку и разместил там запись, мой код перезаписывал предыдущую запись, а это не то, что я хотел. Извините, кажется, я плохо объяснил

Strexxin 11.05.2022 12:16

@Strexxin Хорошо. Я адаптирую код, чтобы по-другому вычислить пустую строку в «A: A», а затем построить диапазон с ее использованием.

FaneDuru 11.05.2022 12:17

@Strexxin Хорошо. Адаптирован код, чтобы сначала вычислить пустую строку, а затем вставить ее. Пожалуйста, протестируйте обновленную версию, но она должна корректно работать и с тем способом, который вы использовали... Если все еще проблематично, если вы не можете поделиться такой книгой (фиктивной), я не могу понять, что происходит в вашей среде. Если у вас есть Anydesk или TeamViewer и принимается удаленное подключение, я сразу пойму, что происходит... Поскольку код работает как надо на моем ноутбуке/книге, я не могу представить, что не так в вашем случае.

FaneDuru 11.05.2022 12:24

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

Strexxin 11.05.2022 12:34

@Strexxin Я только что добавил строку отладки в приведенный выше код. Пожалуйста, запустите его и скажите, что он возвращает в Immediate Window при остановке на этой строке (Debug.Print rngDel.Address, lastRowA: Stop)

FaneDuru 11.05.2022 12:34

@Strexxin Я тоже не могу понять ... До модификации все работало так же. Теперь, если вы считаете, что вам нужно обработать гораздо больший диапазон вставляемых строк, код следует адаптировать для более частой вставки. Я имею в виду, что построение диапазона Union выполняется быстро для 100-200 диапазонов, но код значительно замедляется для больших диапазонов, поэтому хорошо установить лимит и время от времени вставлять и делать rngDel = Nothing...

FaneDuru 11.05.2022 12:37

Другие вопросы по теме