2015-02-18 21 views
9

Tôi có 8 biến trong cột A, 1,2,3,4,5 và A, B, C.lọc ra nhiều tiêu chí sử dụng excel vba

Mục đích của tôi là lọc ra A, B, C và chỉ hiển thị 1-5.

tôi có thể làm điều này bằng cách sử dụng đoạn mã sau:

My_Range.AutoFilter Field:=1, Criteria1:=Array("1", "2", "3","4","5"), Operator:=xlFilterValues 

Nhưng những gì mã lệnh thực hiện là nó lọc biến 1-5 và hiển thị chúng.

tôi wont làm ngược lại, nhưng năng suất kết quả tương tự, bằng cách lọc ra A, B, C và hiển thị các biến 1-5

Tôi đã thử mã này:

My_Range.AutoFilter Field:=1, Criteria1:=Array("<>A", "<>B", "<>C"), Operator:=xlFilterValues 

Nhưng nó đã làm không làm việc.

Tại sao tôi không thể sử dụng mã này?

Nó cho lỗi này:

run time error 1004 autofilter method of range class failed

Làm thế nào tôi có thể thực hiện điều này?

+0

thể trùng lặp của [Excel VBA AutoFilter tất cả ngoại trừ ba] (https://stackoverflow.com/questions/19497659/excel-vba-autofilter-all-but-three/35120033 ? s = 1 | 66.2429 # 35120033) – Jeeped

Trả lời

13

Tôi nghĩ (từ thử nghiệm - MSDN không hữu ích ở đây) rằng không có cách nào trực tiếp để thực hiện việc này. Đặt Criteria1 thành một số Array tương đương với việc sử dụng các hộp đánh dấu trong menu thả xuống - như bạn nói, nó sẽ chỉ lọc danh sách dựa trên các mục khớp với một trong những mục trong mảng đó.

Điều thú vị là, nếu bạn có các giá trị văn chương "<>A""<>B" trong danh sách và bộ lọc bằng các macro recorder đi lên với

Range.AutoFilter Field:=1, Criteria1:="=<>A", Operator:=xlOr, Criteria2:="=<>B" 

mà hoạt động. Nhưng nếu bạn sau đó có giá trị bằng chữ là "<>C" và bạn lọc cho cả ba (sử dụng hộp đánh dấu) trong khi ghi macro, trình ghi macro sao chép chính xác mã của bạn mà sau đó không thành công với lỗi. Tôi đoán tôi sẽ gọi đó là một lỗi - có các bộ lọc bạn có thể làm bằng cách sử dụng giao diện người dùng mà bạn không thể làm với VBA.

Dù sao, hãy quay lại vấn đề của bạn. Có thể lọc các giá trị không bằng một số tiêu chí, nhưng chỉ lên đến hai giá trị mà không làm việc cho bạn:

Range("$A$1:$A$9").AutoFilter Field:=1, Criteria1:="<>A", Criteria2:="<>B", Operator:=xlAnd 

Có một vài cách giải quyết có thể tùy thuộc vào vấn đề chính xác:

  1. Sử dụng "cột trợ giúp" với công thức trong cột B và sau đó lọc trên đó - ví dụ =ISNUMBER(A2) hoặc =NOT(A2="A", A2="B", A2="C") sau đó lọc trên TRUE
  2. Nếu bạn không thể thêm một cột, sử dụng AutoFilter với Criteria1:=">-65535" (hoặc một số thích hợp thấp hơn so với bất kỳ bạn mong đợi) mà sẽ lọc ra các giá trị không phải số - giả sử đây là những gì bạn muốn
  3. Viết một phụ VBA để ẩn các hàng (không chính xác giống như một bộ lọc tự động nhưng nó có thể đủ tùy thuộc vào nhu cầu của bạn).

Ví dụ:

Public Sub hideABCRows(rangeToFilter As Range) 
    Dim oCurrentCell As Range 
    On Error GoTo errHandler 

    Application.ScreenUpdating = False 
    For Each oCurrentCell In rangeToFilter.Cells 
    If oCurrentCell.Value = "A" Or oCurrentCell.Value = "B" Or oCurrentCell.Value = "C" Then 
     oCurrentCell.EntireRow.Hidden = True 
    End If 
    Next oCurrentCell 

    Application.ScreenUpdating = True 
    Exit Sub 

errHandler: 
    Application.ScreenUpdating = True 
End Sub 
+0

Cảm ơn bạn rất nhiều. Đây chính xác là những gì tôi đang tìm kiếm, một câu trả lời mang tính thông tin và giáo dục. Tiếp tục công việc tốt. –

-2

Thay Operator: = xlOr với Operator: = xlAnd giữa tiêu chí của bạn. Xem bên dưới kịch bản sửa đổi

myRange.AutoFilter Dòng: = 1, Criteria1: = "<> A", Operator: = xlAnd, Criteria2: = "<> B", Operator: = xlAnd, Criteria3: =" < > C "

+0

Trước hết, tôi đã tham khảo tài liệu Excel và chức năng AutoFilter không có tham số Criteria3! Và thứ 3, 'A', 'B' và 'C' chỉ là một ví dụ; Tôi có thể cần một mảng với hơn 3 giá trị! – schlebe

0

Tôi không tìm thấy giải pháp nào trên Internet, vì vậy tôi đã triển khai một giải pháp.

Mã Bộ lọc tự động với tiêu chí là sau đó

iColNumber = 1 
Dim aFilterValueArray() As Variant 
Call ConstructFilterValueArray(aFilterValueArray, iColNumber, Array("A", "B", "C")) 

ActiveSheet.range(sRange).AutoFilter Field:=iColNumber _ 
    , Criteria1:=aFilterValueArray _ 
    , Operator:=xlFilterValues 

Trong thực tế, phương pháp ConstructFilterValueArray() (không hoạt động) có được tất cả các giá trị riêng biệt mà nó tìm thấy trong một cột cụ thể và loại bỏ tất cả các giá trị xuất hiện trong tranh luận cuối cùng.

Mã VBA của phương pháp này là

'************************************************************ 
'* ConstructFilterValueArray() 
'************************************************************ 

Sub ConstructFilterValueArray(a() As Variant, iCol As Integer, aRemoveArray As Variant) 

    Dim aValue As New Collection 
    Call GetDistinctColumnValue(aValue, iCol) 
    Call RemoveValueList(aValue, aRemoveArray) 
    Call CollectionToArray(a, aValue) 

End Sub 

'************************************************************ 
'* GetDistinctColumnValue() 
'************************************************************ 

Sub GetDistinctColumnValue(ByRef aValue As Collection, iCol As Integer) 

    Dim sValue As String 

    iEmptyValueCount = 0 
    iLastRow = ActiveSheet.UsedRange.Rows.Count 

    Dim oSheet: Set oSheet = Sheets("X") 

    Sheets("Data") 
     .range(Cells(1, iCol), Cells(iLastRow, iCol)) _ 
      .AdvancedFilter Action:=xlFilterCopy _ 
          , CopyToRange:=oSheet.range("A1") _ 
          , Unique:=True 

    iRow = 2 
    Do While True 
     sValue = Trim(oSheet.Cells(iRow, 1)) 
     If sValue = "" Then 
      If iEmptyValueCount > 0 Then 
       Exit Do 
      End If 
      iEmptyValueCount = iEmptyValueCount + 1 
     End If 

     aValue.Add sValue 
     iRow = iRow + 1 
    Loop 

End Sub 

'************************************************************ 
'* RemoveValueList() 
'************************************************************ 

Sub RemoveValueList(ByRef aValue As Collection, aRemoveArray As Variant) 

    For i = LBound(aRemoveArray) To UBound(aRemoveArray) 
     sValue = aRemoveArray(i) 
     iMax = aValue.Count 
     For j = iMax To 0 Step -1 
      If aValue(j) = sValue Then 
       aValue.Remove (j) 
       Exit For 
      End If 
     Next j 
    Next i 

End Sub 

'************************************************************ 
'* CollectionToArray() 
'************************************************************ 

Sub CollectionToArray(a() As Variant, c As Collection) 

    iSize = c.Count - 1 
    ReDim a(iSize) 

    For i = 0 To iSize 
     a(i) = c.Item(i + 1) 
    Next 

End Sub 

Mã này chắc chắn có thể được cải thiện trong trả lại một mảng của chuỗi nhưng làm việc với mảng trong VBA là không dễ dàng.

THẬN TRỌNG: mã này chỉ hoạt động nếu bạn xác định trang tính có tên X vì tham số CopyToRange được sử dụng trong AdvancedFilter() cần có Phạm vi Excel!

Thật đáng tiếc khi Microfsoft không triển khai giải pháp này trong việc thêm đơn giản enum mới là xlNotFilterValues! ... hoặc xlRegexMatch!

0

Alternative sử dụng chức năng lọc VBA của

Là một thay thế sáng tạo để @schlebe 's câu trả lời gần đây, tôi cố gắng sử dụng Filter chức năng tích hợp trong VBA, cho phép để lọc ra một tìm kiếm nhất chuỗi thiết lập đối số thứ ba thành False. Tất cả các chuỗi tìm kiếm "phủ định" tìm kiếm (ví dụ: A, B, C) được xác định trong một mảng. Tôi đọc các tiêu chí trong cột A đến một mảng datafield và thực thi cơ bản một bộ lọc tiếp theo (A - C) để lọc các mục này ra ngoài.

Sub FilterOut() 
Dim ws As Worksheet 
Dim rng As Range, i As Integer, n As Long, v As Variant 
' 1) define strings to be filtered out in array 
    Dim a()     ' declare as array 
    a = Array("A", "B", "C") ' << filter out values 
' 2) define your sheetname and range (e.g. criteria in column A) 
    Set ws = ThisWorkbook.Worksheets("FilterOut") 
    n = ws.Range("A" & ws.Rows.Count).End(xlUp).row 
    Set rng = ws.Range("A2:A" & n) 
' 3) hide complete range rows temporarily 
    rng.EntireRow.Hidden = True 
' 4) set range to a variant 2-dim datafield array 
    v = rng 
' 5) code array items by appending row numbers 
    For i = 1 To UBound(v): v(i, 1) = v(i, 1) & "#" & i + 1: Next i 
' 6) transform to 1-dim array and FILTER OUT the first search string, e.g. "A" 
    v = Filter(Application.Transpose(Application.Index(v, 0, 1)), a(0), False, False) 
' 7) filter out each subsequent search string, i.e. "B" and "C" 
    For i = 1 To UBound(a): v = Filter(v, a(i), False, False): Next i 
' 8) get coded row numbers via split function and unhide valid rows 
    For i = LBound(v) To UBound(v) 
     ws.Range("A" & Split(v(i) & "#", "#")(1)).EntireRow.Hidden = False 
    Next i 
End Sub 
Các vấn đề liên quan