Excel 2013 macro to show only specific rows based on one cell value

扶醉桌前 提交于 2020-01-15 12:31:07

问题


i am new to excel macros and vba. I have an excel file with about 300000 rows in first sheet where there are item identifiers in first column(they might be several which has the same value), and about 1000 rows in second sheet(first column also contains item identifiers but they are unique here). i need to write a macro that hides rows in first sheet based on the second sheet. i mean i need to loop throw all rows in first sheet and if first cell value does not match any cell of first column of the second sheet then hide this row.

i know that it will be very slow as everytime i need to compare cellvalue with another 1000 cell values, and i have 300 000 rows. How can i do it? could you please suggest the fastest way? any help would be appreciated, thanks in advance.

EDIT after searching a lot i made my own macro

Sub hide()    
Dim MyCell, Rng As Range, Rn2 As Range
Dim MyCell2
Dim id(1 To 1392) As String
Set Rng = Sheets("Sheet0").Range("C162403:C339579")
Set Rng2 = Sheets("IT stuff").Range("A1:A22031")
i = 1
For Each MyCell2 In Rng2
    If Not MyCell2.EntireRow.Hidden Then
        id(i) = MyCell2.Value
        i = i + 1
    End If
Next MyCell2
j = 0
For Each MyCell In Rng
    For A = 1 To 1392
        If MyCell = id(A) Then
        j = 1
        End If
    Next A
    If j = 0 Then
        MyCell.EntireRow.Hidden = True
    ElseIf j = 1 Then
        j = 0
    End If
Next MyCell
End Sub

it is processing now my excel file, however it is very slow... how can i improve it??


回答1:


Making calls to the Excel object model slows things considerably so it's probably best to load the values you want to check for into a dictionary or array and reference that instead. You could also load the row number and value of the rows you are checking in another dictionary and cross reference the two data structures while making note of the rows you need to hide. Working this way will take up quite a bit of memory but will definitely be faster than cross referencing sheets directly...

hth




回答2:


Why VBA? And not Excel Formula(Vlookup) + Autofilter

Let's say your Sheet 1 looks like this

And sheet 2 looks like this

Simply Add a Column as shown below and put the formula and then use Autofilter to Hide the relevant rows.

Formula used in I2 is

=IF(ISERROR(VLOOKUP(A2,Sheet2!A:A,1,0)),"","True")



回答3:


The following code takes a somewhat different approach to your problem. You will note that it assumes that Sheet1 has a set of values in column A plus an unspecified number of data columns and that Sheet2 has only a a set of values in column A against which the Sheet1 column A values are matched.

The code does the following:

  • Creates match values in the column to the right of the last data column in worksheet 1 (1 = no-match, 0 = match)
  • Sets an autofilter on the sheet 1 data range, with a criterion value of 1 on the match column (i.e., filter to show only no-matches)
  • Assigns the filtered rows to a range variable
  • Removes the filter and clears the match column
  • Hides in bulk the rows identified in the range variable

I tested the procedure with a Sheet1 dataset of 300,000 rows of code values in column A and random numeric data in columns B and C, with just over 1,000 match values in Sheet2. The randomly generated 10-character code and match values were constructed so that 20 percent of the Sheet1 column A values were non-matches.

Run times against these data averaged under two minutes.

Sub MatchFilterAndHide2()

    Dim calc As Variant
    Dim ws1 As Worksheet, ws2 As Worksheet
    Dim ws1Name As String, ws2Name As String
    Dim rng1 As Range, rng2 As Range
    Dim hideRng As Range
    Dim lastRow1 As Long, lastRow2 As Long
    Dim lastCol1 As Long

    Application.ScreenUpdating = False
    calc = Application.Calculation
    Application.Calculation = xlCalculationManual

    ws1Name = "Sheet1"
    Set ws1 = Worksheets(ws1Name)
    With ws1
        lastRow1 = .Range("A" & .Rows.Count).End(xlUp).Row
        lastCol1 = .Cells(1, ws1.Columns.Count).End(xlToLeft).Column + 1
        Set rng1 = .Range(.Cells(1, 1), .Cells(lastRow1, lastCol1))
    End With

    ws2Name = "Sheet2"
    Set ws2 = Worksheets(ws2Name)
    With ws2
        lastRow2 = .Range("A" & .Rows.Count).End(xlUp).Row
        Set rng2 = .Range("A2:A" & lastRow2)
    End With

    'add column of match values one column to the right of last data column
    '1 = no-match, 0 = match
    With ws1.Range(ws1.Cells(2, lastCol1), ws1.Cells(lastRow1, lastCol1))
        .FormulaArray = "=N(ISNA(MATCH(" & ws1Name & "!" & rng1.Address & _
            "," & ws2Name & "!" & rng2.Address & ",0)))"
        .Value = .Value
    End With

    'set autofilter on rng1 and filter to show the no-matches
    With ws1.Range(ws1.Cells(1, 1), ws1.Cells(1, lastCol1))
        .AutoFilter
        .AutoFilter field:=lastCol1, Criteria1:=1
    End With

    With ws1
        'assign no-matches to range object
        Set hideRng = .Range("A2:A" & lastRow1).SpecialCells(xlCellTypeVisible)

        'turn off autofilter, clear match column, and hide no-matches
        .AutoFilterMode = False
        .Cells(1, lastCol1).EntireColumn.Clear
        hideRng.EntireRow.Hidden = True
        .Cells(1, 1).Select
    End With

    Application.Calculation = calc
    Application.ScreenUpdating = True
End Sub


来源:https://stackoverflow.com/questions/18099778/excel-2013-macro-to-show-only-specific-rows-based-on-one-cell-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!