I'm trying to compare two lists of products. I want to delete the entire row in Sheet1 if a match is made from Sheet2.
Sheet1 (has 17226 rows)
ITEMID WAREHOUSEID QUANTITY UNIT PRICE LOCATIONID
1000 1 100 EA 1.00 30
1001 1 100 EA 1.00 30
1002 1 100 EA 1.00 30
1003 1 100 EA 1.00 30
1004 1 100 EA 1.00 30
1005 1 100 EA 1.00 30
1006 1 100 EA 1.00 30
1007 1 100 EA 1.00 30
1008 1 100 EA 1.00 30
Sheet2 (has 977 rows)
1002
1004
1006
1008
I believe it'd work if I iterate through the values in Column A of Sheet2 and compare them against each ITEMID in Sheet1 (this is Column E in Sheet1).
I wrote this code, but it doesn't seem to do anything:
Sub Delete()
Dim LastRow As Long
Dim i As Long
Dim rngCell As Range
LastRow = Range("Sheet1!E17226").End(xlUp).Row
For Each rngCell In Range("Sheet2!A1:A977")
For i = LastRow To 1 Step -1
If Range("E" & i).Value = rngCell.Value Then
Range("E" & i).EntireRow.Delete
End If
Next
Next
End Sub
Please point out my mistake so I can fix and run the VBA script, thank you.
CodePudding user response:
Delete Rows
Basic (Two Loops)
Sub BasicTwoLoops() ' slow (takes forever)
Const sfRow As Long = 2
Const sCol As String = "A"
Const dfRow As Long = 2
Const dCol As String = "E"
Dim sws As Worksheet: Set sws = Sheet2
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, "A").End(xlUp).Row
Dim dws As Worksheet: Set dws = Sheet1
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, "E").End(xlUp).Row
Dim sValue As Variant
Dim sr As Long
Dim dValue As Variant
Dim dr As Long
For dr = dlRow To dfRow Step -1
dValue = dws.Cells(dr, dCol).Value
For sr = sfRow To slRow
sValue = sws.Cells(sr, sCol).Value
If dValue = sValue Then
dws.Cells(dr, dCol).EntireRow.Delete
Exit For
End If
Next sr
Next dr
End Sub
Application.Match feat. Range.Union
Sub UseRangesWithUnion() ' fast
' Uses 'RefCombinedRange'
Const sfRow As Long = 2
Const sCol As String = "A"
Const dfRow As Long = 2
Const dCol As String = "E"
Dim sws As Worksheet: Set sws = Sheet2
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, "A").End(xlUp).Row
Dim srCount As Long: srCount = slRow - sfRow 1
Dim srg As Range: Set srg = sws.Cells(sfRow, sCol).Resize(srCount)
Dim dws As Worksheet: Set dws = Sheet1
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, "E").End(xlUp).Row
Dim drCount As Long: drCount = dlRow - dfRow 1
Dim drg As Range: Set drg = dws.Cells(dfRow, dCol).Resize(drCount)
Dim sCell As Range
Dim sIndex As Variant
Dim ddrg As Range
Dim dCell As Range
Dim dValue As Variant
For Each dCell In drg.Cells
dValue = dCell.Value
sIndex = Application.Match(dValue, srg, 0)
If IsNumeric(sIndex) Then
Set ddrg = RefCombinedRange(ddrg, dCell)
End If
Next dCell
If ddrg Is Nothing Then Exit Sub
ddrg.EntireRow.Delete
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Creates a reference to a range combined from two ranges.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function RefCombinedRange( _
ByVal CombinedRange As Range, _
ByVal AddRange As Range) _
As Range
If CombinedRange Is Nothing Then
Set RefCombinedRange = AddRange
Else
Set RefCombinedRange = Union(CombinedRange, AddRange)
End If
End Function
Range.AutoFilter
Sub UseAutoFilter() ' fastest
' Uses 'GetColumnRange'
' Uses 'ArrStringDataColumn'
' Source headers are not included in the range.
' Destination headers are included in the range.
Const sfRow As Long = 2
Const sCol As String = "A"
Const dfRow As Long = 1 ' Headers included
Const dCol As String = "E"
Dim sws As Worksheet: Set sws = Sheet2
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, "A").End(xlUp).Row
Dim srCount As Long: srCount = slRow - sfRow 1
Dim srg As Range: Set srg = sws.Cells(sfRow, sCol).Resize(srCount)
Dim sData As Variant: sData = GetColumnRange(srg) ' 2D one-based
Dim sArr As Variant: sArr = ArrStringDataColumn(sData, 1) ' 1D zero-based
If IsEmpty(sArr) Then Exit Sub
Dim dws As Worksheet: Set dws = Sheet1
dws.AutoFilterMode = False
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, "E").End(xlUp).Row
Dim drCount As Long: drCount = dlRow - dfRow 1
Dim drg As Range: Set drg = dws.Cells(dfRow, dCol).Resize(drCount)
Dim ddrg As Range: Set ddrg = drg.Resize(drg.Rows.Count - 1).Offset(1)
drg.AutoFilter 1, sArr, xlFilterValues
On Error Resume Next
ddrg.SpecialCells(xlCellTypeVisible).EntireRow.Delete
On Error GoTo 0
dws.AutoFilterMode = False
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the values of a column of a 2D array, converted to
' a string, in an array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function ArrStringDataColumn( _
ByVal sData As Variant, _
ByVal sColumnIndex As Long, _
Optional ByVal dFirstIndex As Long) _
As Variant
Const ProcName As String = "ArrDataColumn"
On Error GoTo ClearError
Dim sLower As Long: sLower = LBound(sData, 1)
Dim sUpper As Long: sUpper = UBound(sData, 1)
Dim IndexDiff As Long: IndexDiff = sLower - dFirstIndex
Dim dArr As Variant: ReDim dArr(dFirstIndex To sUpper - IndexDiff)
Dim r As Long
For r = sLower To sUpper
dArr(r - IndexDiff) = CStr(sData(r, sColumnIndex))
Next r
ArrStringDataColumn = dArr
ProcExit:
Exit Function
ClearError:
Debug.Print "'" & ProcName & "': Unexpected Error!" & vbLf _
& " " & "Run-time error '" & Err.Number & "':" & vbLf _
& " " & Err.Description
Resume ProcExit
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Writes the values from a column ('ColumnNumber')
' of a range ('rg') to a 2D one-based array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function GetColumnRange( _
ByVal rg As Range, _
Optional ByVal ColumnNumber As Long = 1) _
As Variant
If rg Is Nothing Then Exit Function
If ColumnNumber < 1 Then Exit Function
If ColumnNumber > rg.Columns.Count Then Exit Function
With rg.Columns(ColumnNumber)
If rg.Rows.Count = 1 Then
Dim Data As Variant: ReDim Data(1 To 1, 1 To 1): Data(1, 1) = .Value
GetColumnRange = Data
Else
GetColumnRange = .Value
End If
End With
End Function
CodePudding user response:
Maybe something like this?
Note how explicit the Range references are. For example, where you have If Range("E" & i).Value in your code, that Range object implicitly attaches to the ActiveSheet, which could be Shee1 or Sheet2.
Public Sub Delete()
Dim rng1 As Range, rng2 As Range, r1 As Range, r2 As Range
Set rng1 = ThisWorkbook.Worksheets("Sheet1").Range("A1:A17226")
Set rng2 = ThisWorkbook.Worksheets("Sheet2").Range("A1:A997")
For Each r2 In rng2
Set r1 = rng1.Find(What:=r2.Value, LookAt:=xlWhole)
If Not r1 Is Nothing Then
r1.EntireRow.Delete
End If
Next
End Sub
