Delete rows based on condition in a column

雨燕双飞 提交于 2020-01-23 17:23:06

问题


I've searched online and on here but can't find anything which seems to fit the bill and work. I have got some code which works but because the length of the range changes as it deletes rows it doesn't catch all of the rows to delete and so I end up running it several times which isn't great...so I'm now trying the AutoFilter approach as recommended on this thread.

I have a spreadsheet with several columns, one of which is 'cost'. I need to go through the 'cost' column (which can sometimes be column 9, sometimes 10, hence the 'find' bit below) and delete any row where the cost is 0...

Below is the code I've written so far, any help would be very, very much appreciated!!!!

-- edit 3: some more code changes have been made...new code is below.

Sub RemoveRows()
    Dim cell As Range
    Dim lastRow As Long
    Dim lastColumn As Integer
    Dim criteraColumn As Integer
    Dim criteriaRange As Range

    lastRow = Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).row
    lastColumn = Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column

    Rows(1).EntireRow.Select
    criteriaColumn = Selection.Find(What:="Cost", After:=ActiveCell, LookIn:= _
                        xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:= _
                        xlNext, MatchCase:=False, SearchFormat:=False).Column
    Set criteriaRange = Range("A1", Cells(lastRow, lastColumn))

    criteriaRange.AutoFilter Field:=criteriaColumn, Criteria1:="£0.00"
    AutoFilter.Range.Delete
    ActiveSheet.AutoFilterMode = False
End Sub

When I run this, it applies the filter on the correct range and to the correct column. I then get the error message: "Run-time error '424': Object required" which applies to the AutoFilter.Range.Delete line. When I press 'end' or 'debug' on this and look at the spreadsheet, the filter has been applied to the correct column and the correct option (£0.00) is checked, but no results are returned (I know I need to do some error handling in case of this situation in future but for now there should be at least 10 lines returned by this filter). If I manually press 'OK' on the filter settings in the spreadsheet (without changing any of them!) my 10 results show up correctly so I'm not sure why they're not showing up when I do this programmatically?

Happy to supply spreadsheet example if required, this is really confusing me!!

Spreadsheet can be found here


回答1:


You should be able to use the Excel AutoFilter to delete the rows.

Cells.AutoFilter Field:=criteriaColumn, Criteria1:="£0.00"
ActiveSheet.AutoFilter.Range.Offset(1).Delete
ActiveSheet.ShowAllData

This will filter for cost = 0 and then delete all the rows that match the filter.

The operater is automatically equals so you don't need "=£0.00" as the parameter.

I added in the ActiveSheet for AutoFilter to get rid of the object not found, and the Offset makes it not delete headers.




回答2:


I would do it in another way, for performance reasons (reading + deleting line by line is slow). I answered a similar question before, I think it is also quite applicable for your post.

What I would suggest that you could do:

  • Instead of reading the sheet row by row, load the entire range into an array once;
  • Instead of deleting row by row, transport the values you need into a second array in memory;
  • When you have the data you need, apply a oRange.clearcontents to clear the current range;
  • Display the new array of data into the sheet by applying oRange = vArray.

Reading / transforming data are performed in memory, and read and write are only performed once.

In this thread, you have the code I wrote before: Execution of VBA code gets slow after many iterations

Let me know if this could help you out, or if you wish to receive more concrete info / code.




回答3:


What you need to do is to step backward through the range, since deleting rows automatically moves rows up one by default in Excel.

Replace:

   For Each cell In criteriaRange.Cells
        If cell.Value = 0 Then
            cell.EntireRow.Delete
        End If
    Next cell

With:

Dim i As Integer

For i = criteriaRange.Rows.Count To 1 Step -1
    If criteriaRange.Cells(i) = 0 Then
        criteriaRange.Cells(i).EntireRow.Delete
    End If
Next

Also, ScreenUpdating has no effect on the methods of a macro. It basically turns off "screen-flickering" for every action the macro takes, making it run faster and smoother for the user experience.




回答4:


You could have it so whenever it deletes a row, it either goes back to the top of the column or you could subtract one from the count. Either way, it wouldn't skip any rows. I'd provide actual code but I'm new with VBA and wouldn't quite know how to do that.



来源:https://stackoverflow.com/questions/11562093/delete-rows-based-on-condition-in-a-column

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