Макрос VBA для фильтрации, скопируйте указанное значение из столбца и создайте, затем вставьте в новый лист с этим именем столбца

#excel #vba

#excel #vba

Вопрос:

Я очень новичок в макросе VBA. Я закодировал приведенный ниже макрос, который фильтрует столбец «N», содержащий «Океан», и копирует соответствующие ему данные. Затем он создает новый лист с именем «Ocean» и вставляет туда данные.

Или можно отфильтровать столбец N, содержащий «Океан», и удалить несоответствующие данные? Пожалуйста, помогите. Ниже приведен мой код и скриншот Excel для справки.

 Dim Wf As Workbook
Dim Tsht As Worksheet, FSht As Worksheet
Dim lRow As Long, lRw As Long

Set Wf = ActiveWorkbook
Set Tsht = Wf.Sheets("Main")

With Tsht
        lRow = .Cells(.Rows.Count, "N").End(xlUp).Row
    End With
    
Application.AskToUpdateLinks = False


Set FSht = Wf.Sheets("Ocean")

    With FSht
        .AutoFilterMode = False
        lRw = .Cells(.Rows.Count, "C").End(xlUp).Row
        .Range("A" amp; lRw).AutoFilter Field:=2, Criteria1:="Ocean"
        .AutoFilter.Range.Copy

      End With 
  

Столбец N

Я хочу, чтобы макрос разделял только строки, содержащие Ocean, на новом листе с именем листа «Ocean». Или макрос должен сохранять только данные, соответствующие Ocean, и удалять остальные… Пожалуйста, помогите………..

Комментарии:

1. Я думаю, что ответ на этот вопрос будет основан на вашем наборе данных. Сколько строк вы ожидаете на листе? Причина, по которой я спрашиваю об этом, заключается в том, что обычно рекомендуется удалять строки снизу вверх. Но если у вас более 500 тыс. строк на листе, это может занять некоторое время. Кроме того, если вы используете фильтр, этот подход не будет работать. Таким образом, вы могли бы использовать массивный подход (получить ваши данные в массиве, удалить из массива и установить их обратно на свой лист). Опять же, если у вас большой набор данных, вы можете рассмотреть комбинацию массива и Range.Find подхода

Ответ №1:

Копирование с автофильтром

При этом рабочий лист будет удален Ocean , если он существует. Затем он добавит новый лист, назовет его Ocean и скопирует отфильтрованные данные с листа Main на него.

Код

 Option Explicit

Sub AutoFilterCopy()

    Application.AskToUpdateLinks = False
    
    Dim wb As Workbook
    ' If the code is in the ActiveWorkbook you should use ThisWorkbook instead.
    Set wb = ActiveWorkbook
        
    ' Delete Target Worksheet.
    Dim FSht As Worksheet
    On Error Resume Next
    Set FSht = wb.Worksheets("Ocean")
    If Err.Number = 0 Then
        Application.DisplayAlerts = False
        FSht.Delete
        Application.DisplayAlerts = True
    End If
    On Error GoTo 0
    
    ' Define Target Worksheet.
    Set FSht = wb.Worksheets.Add(After:=wb.Worksheets(wb.Worksheets.Count))
    FSht.Name = "Ocean"
    
    ' Define Source Worksheet.
    Dim Tsht As Worksheet
    Set Tsht = wb.Worksheets("Main")
    With Tsht
        If .AutoFilterMode Then
            .AutoFilterMode = False
        End If
        ' 14 is column N
        .Range("A1").AutoFilter Field:=14, Criteria1:="Ocean"
        .AutoFilter.Range.Copy FSht.Range("A1")
    End With
    
    MsgBox "Worksheet created, data copied.", vbInformation, "Success"
    
End Sub
  

Редактировать:

  • Вместо столбца N (14) OP хочет идентифицировать столбец критериев с его заголовком: «Режим».

Отредактированный код

 Option Explicit

Sub AutoFilterCopy()

    Application.AskToUpdateLinks = False
    
    Dim wb As Workbook
    ' If the code is in the ActiveWorkbook you should use ThisWorkbook instead.
    Set wb = ActiveWorkbook
        
    ' Delete Target Worksheet.
    Dim FSht As Worksheet
    On Error Resume Next
    Set FSht = wb.Worksheets("Ocean")
    If Err.Number = 0 Then
        Application.DisplayAlerts = False
        FSht.Delete
        Application.DisplayAlerts = True
    End If
    On Error GoTo 0
    
    ' Define Target Worksheet.
    Set FSht = wb.Worksheets.Add(After:=wb.Worksheets(wb.Worksheets.Count))
    FSht.Name = "Ocean"
    
    ' Define Source Worksheet.
    Dim Tsht As Worksheet
    Set Tsht = wb.Worksheets("Main")
    With Tsht
        If .AutoFilterMode Then
            .AutoFilterMode = False
        End If
        Const FieldName As String = "Mode"
        Dim FieldNumber As Long
        ' Note that there will be an error if "Mode" cannot be found.
        FieldNumber = Application.Match(FieldName, .Rows(1), 0)
        .Range("A1").AutoFilter Field:=FieldNumber, Criteria1:="Ocean"
        .AutoFilter.Range.Copy FSht.Range("A1")
    End With
    
    MsgBox "Worksheet created, data copied.", vbInformation, "Success"
    
End Sub
  

Комментарии:

1. Это идеально! Большое спасибо @VBasic2008… Ценю вашу помощь …. еще раз спасибо.

2. Есть ли шанс, что мы можем указать имя столбца «Mode» вместо 14 на случай, если столбец изменится, ошибки не будет. 14 — столбец N .Диапазон («A1»).Поле автофильтра: = 14, Критерий1: = «Океан»

3. @JaySameer: я добавил другую версию, как вы просили.

Ответ №2:

Вот еще один вариант использования Range.Find . Обычно я стараюсь избегать жесткого кодирования строк и столбцов, когда это возможно. Вы увидите, где я искал строку заголовка для «Режима». Это позволяет изменять порядок столбцов без нарушения кода.

Я бы изменил свой код, увидев ответ, предоставленный @VBasic2008. Я бы использовал этот .AutoFilter.Copy метод, а не перебирал каждое совпадение. Мне также нравится, как он проверил, существует ли лист с нужным режимом.

Удачи!

 Public Sub ExtractDataByMode()

Const mode = "Ocean"

Dim mainWS As Worksheet
Set mainWS = ThisWorkbook.Worksheets("Main")
Dim hdrRow As Range
Set hdrRow = Intersect(mainWS.Rows(1), mainWS.UsedRange)

Dim modeColIdx As Integer
modeColIdx = hdrRow.Find(What:="Mode", lookat:=xlWhole, _
    MatchCase:=False).Column
    
Dim modeColRng As Range
Set modeColRng = Intersect(mainWS.Columns(modeColIdx), mainWS.UsedRange)

Dim firstMatch As Range
Set firstMatch = modeColRng.Find(What:=mode, lookat:=xlWhole, _
    MatchCase:=False)
    
Dim modeWS As Worksheet
Set modeWS = ThisWorkbook.Worksheets.Add( _
    After:=ThisWorkbook.Worksheets( _
    ThisWorkbook.Worksheets.Count))
modeWS.Name = mode
hdrRow.Copy modeWS.Cells(1, 1)

Dim match As Range
Dim nextRow As Integer
Dim matchRow As Range
Set match = firstMatch
nextRow = modeWS.UsedRange.Rows.Count   1
Do
    Set matchRow = Intersect(mainWS.Rows(match.Row), mainWS.UsedRange)
    matchRow.Copy modeWS.Cells(nextRow, 1)
    Set match = modeColRng.FindNext(match)
    nextRow = modeWS.UsedRange.Rows.Count   1

Loop While match.Address <> firstMatch.Address

End Sub
  

Комментарии:

1. Отлично, спасибо @BoilermakerRV

2. Привет, он создает новый лист с именем ocean правильно …. но сразу после того, как он переходит к следующему циклу, он становится слишком медленным для выполнения или в следующем цикле, это занимает 2-3 минуты

3. приведенный выше код работает нормально, но после завершения работы этого модуля он зависает примерно на 4-5 минут, а затем повторяется

4. Для меня это было нормально, но только с 28 строками случайно сгенерированных целых чисел. Я думаю, что этот .AutoFilter.Copy вариант может быть более эффективным с большим набором данных.

5. Или это возможно, как вместо создания нового листа с именем «Океан»! Он выбирает значение из режима столбца как «Океан» и удаляет остальные все данные и сохраняет только данные, соответствующие режиму ocean, на том же «Основном» листе.