Автофильтр с двойным циклом, работает ли это в Excel VBA?

#excel #vba #autofilter

#excel #vba #автофильтр

Вопрос:

У меня есть набор данных из базы данных, импортированных в файл Excel. Эти данные получены с лазерного станка для резки металла. Имеющиеся у меня данные включают название материала, толщину пластины и 2 разных времени (данных больше, но мне нужны именно эти 4).

Результат, который я хочу: сначала я хочу отфильтровать свои данные по названию материала, после этого я хочу отфильтровать свои данные по толщине пластины. В результатах этого второго фильтра я хочу суммировать время обоих временных полей, а затем опубликовать результат этого на другом листе. Итак, результатом на втором листе должно быть: название материала, толщина пластины, общее время получения результатов в столбце D, общее время получения результатов в столбце E (в других столбцах есть некоторые данные, которые не имеют значения для этого)

Вот небольшой пример того, как выглядят данные (данные начинаются со строки 3):

 Material name(col A)Plate Thickness(col B)Time1(col D)Time2(col E)
RVS 304             25mm                  00:18:14    00:21:48
RVS 304             25mm                  00:30:28    00:39:19
RVS 304             10mm                  00:12:10    00:14:25
S235                10mm                  00:48:32    00:13:33
S235                3mm                   00:10:31    00:02:22
  

Некоторая другая полезная информация:
Название материала, на котором основан мой цикл, основано на моих результатах и отфильтровано по дубликатам, поэтому имя материала всегда существует. Толщина пластины имеет стандартное количество элементов. Количество элементов в этом диапазоне составляет 19 различных размеров в миллиметрах. Мои списки критериев фильтрации начинаются с ячейки 2, вот почему целое число также начинается с 2. Результат обоих автофильтров может ни к чему не привести, поскольку не каждое название материала соответствует толщине пластины.

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

Это мой код:

 Sub TestSub()
On Error Resume Next
    Worksheets("InformatieData").ShowAllData
On Error GoTo 0
Dim iLoop As Integer

For iLoop = 1 To 20

Worksheets("InformatieData").Range("A2").AutoFilter Field:=1, Criteria1:=Worksheets("InformatieFormules").Cells(iLoop, 1).Value
If Worksheets("InformatieData").AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Count > 1 Then
    Dim mmLoop As Integer

    For mmLoop = 2 To 20
        Worksheets("InformatieData").Range("A2").AutoFilter Field:=2, Criteria1:=Worksheets("InformatieFormules").Cells(mmLoop, 2).Value
        If Worksheets("InformatieData").AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Count > 1 Then
            Worksheets("InformatieData").Range("A3:A10000,B3:B10000,D3:D10000,E3:E10000").Copy
            Worksheets("InformatieMMFilterResultaat").Cells(Cells.Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial (xlPasteValues)
        End If
    Next mmLoop
End If
Next iLoop
End Sub
  

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

1. Зачем вам нужна фильтрация? Я полагаю, что вы могли бы использовать свой код в строках… Получите все, что вам нужно для суммирования на листе, и просто SUMIF . Я что-то не так понимаю, где вам нужны фильтры?

2. Здравствуйте, извините за поздний ответ и спасибо, что написали этот код там! Просто мне показалось, что я должен был сделать это с помощью VBA вместо формулы Excel. Из-за того, что мой Excel написан на моем родном языке (голландский) Я часто забываю самые простые формулы.

3. Я действительно думаю, что SUMIFS сделает эту работу за меня, хотя, если нет, я, защищаясь, вернусь и придумаю свой выход с вашим кодом. Хотя большое спасибо за быстрый ответ!

4. Если вы думаете, что SUMIF этого не сделает, просто попробуйте приведенный ниже код. Но я думаю, вам нужно внести некоторые исправления в код, касающийся столбцов и так далее.

Ответ №1:

Не удалось протестировать это, но я думаю, что это должно работать, по крайней мере, до части разделения (если что-то пойдет не так, вы могли бы найти другой способ или просто использовать опцию интерфейса для преобразования текста в столбцы):

 Option Explicit
Sub Test()

    Dim wsData  As Worksheet, wsOutput As Worksheet, arrData As Variant, SplitRange As Range, i As Long
    'You will need to check Microsoft Scripting Dictionary from your references for this to work:
    Dim DictColD As New Scripting.Dictionary, DictColE As New Scripting.Dictionary

    'Set the worksheets where we will work
    With ThisWorkbook
        Set wsData = .Sheets("InformatieData")
        Set wsOutput = .Sheets("InformatieMMFilterResultaat")
    End With

    'Fill an array with the source data
    arrData = wsData.UsedRange.Value 'this will get everything on the worksheet till the last used cell

    'Lets assume, as you said that the order and position of the columns is A to E
    For i = 2 To UBound(arrData) '2 because 1 is headers
        'if the material with the thickness doesn't exist yet, add it along with its time on column D
        If Not DictColD.Exists(arrData(i, 1) amp; "-" amp; arrData(i, 2)) Then
            DictColD.Add arrData(i, 1) amp; "-" amp; arrData(i, 2), arrData(i, 4) 'Column D value
        Else
        'If the material with the thickness already exists, then sum its time on column D
            DictColD(arrData(i, 1) amp; "-" amp; arrData(i, 2)) = DictColD(arrData(i, 1) amp; "-" amp; arrData(i, 2))   arrData(i, 4)
        End If

        'Now the same for column E
        'if the material with the thickness doesn't exist yet, add it along with its time on column E
        If Not DictColE.Exists(arrData(i, 1) amp; "-" amp; arrData(i, 2)) Then
            DictColE.Add arrData(i, 1) amp; "-" amp; arrData(i, 2), arrData(i, 5) 'Column E value
        Else
        'If the material with the thickness already exists, then sum its time on column E
            DictColE(arrData(i, 1) amp; "-" amp; arrData(i, 2)) = DictColE(arrData(i, 1) amp; "-" amp; arrData(i, 2))   arrData(i, 5)
        End If
    Next i

    Erase arrData

    'Now you've got 2 dictionaries along with all the data you need, you only need to throw it back to your sheet
    With wsOutput 'I'm going to assume you already have the headers there so only the data will be pasted
        .Cells(2, 1).Resize(DictColD.Count) = Application.Transpose(DictColD.Keys) 'Material amp; Thickness
        .Cells(2, 4).Resize(DictColD.Count) = Application.Transpose(DictColD.Items) 'Col D Times
        .Cells(2, 5).Resize(DictColE.Count) = Application.Transpose(DictColE.Items) 'Col E Times
        'Now we need to separate material amp; thickness into 2 columns
        Set SplitRange = .Range("A2", .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, 1))
        SplitRange.TextToColumns Destination:=SplitRange, DataType:=xlDelimited, _
        TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
        Semicolon:=False, Comma:=False, Space:=False, Other:=True, OtherChar _
        :="-", FieldInfo:=Array(Array(1, 1), Array(2, 1)), TrailingMinusNumbers:=True
    End With

End Sub
  

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