Removing ALL Duplicates Row in VBA - vba

I am looking to find out how I can remove ALL duplicate rows (when duplicates exist in the first column) using a VBA macro.
Currently Excel macros delete all duplicate instances EXCEPT for the first instance, which is totally not what I want. I want absolute removal.

A bit shorter solution done for quick morning training:
Sub quicker_Option()
Dim toDel(), i As Long
Dim RNG As Range, Cell As Long
Set RNG = Range("a1:a19") 'set your range here
For Cell = 1 To RNG.Cells.Count
If Application.CountIf(RNG, RNG(Cell)) > 1 Then
ReDim Preserve toDel(i)
toDel(i) = RNG(Cell).Address
i = i + 1
End If
Next
For i = UBound(toDel) To LBound(toDel) Step -1
Range(toDel(i)).EntireRow.Delete
Next i
End Sub

Store the first instance's cell for later deleting.
Then go deleting duplicates until the end.
Dim F as integer, S as integer 'indices for First and Second cells to be compared
Dim Deleted as boolean 'indicates if second line was deleted
Dim First as Range, Second as Range 'First and second cells to be compared
Dim Start as string 'Indicates the position of the first cell's start
Start = "A1" 'can be as you like
Set First = Sheet1.Range(Start) 'Sets the start cell
F = 0 '
Do While First.Value <> "" 'loop while sheet contains data in the column
S = F + 1 'second cell is at least 1 cell below first cell
Deleted = false 'no second cell was deleted yet
Set Second = First.Offset(S,0) 'second cell is an offset of the first cell
Do While Second.Value <> "" 'loop while second cell is in sheet's range with data
if Second.Value = First.Value then 'if values are duplicade
Second.EntreRow.Delete 'delete second cell
Deleted = true 'stores deleted information
else 'if not, second cell index goes next
S = S + 1;
end if
Set Second = First.Offset(S, 0) 'sets second cell again (if deleted, same position, if not deleted, next position
Loop
if Deleted then 'if deleted, should delete first cell as well
First.EntireRow.Delete
else
F = F + 1 'if no duplicates found, first cell goes next
end if
Set First = Sheet1.Range(Start).Offset(F,0) 'sets first cell again (if deleted, same position, if not, next)
Loop

I am using this code to create an Auto reconciliation of general ledger control accounts where if any cell with equal value but opposite sign is cut to sheet 2; hence left with only reconciliation item.
the code:
sub autoRecs()
dim i as long
Application.ScreenUpdating = False
Application.StatusBar = True
Dim i As Long
Cells(5, 6).Select
Dim x As Long
Dim y As Long
x = ActiveCell.Row
y = x + 1
Do Until Cells(x, 6) = 0
Do Until Cells(y, 6) = 0
Application.StatusBar = "Hey Relax! You can rely on me......"
If Cells(x, 6) = Cells(y, 6) * -1 Then
Cells(x, 6).EntireRow.Cut (Worksheets(2).Cells(x, 6).EntireRow)
Cells(y, 6).EntireRow.Cut (Worksheets(2).Cells(y, 6).EntireRow)
Cells(x, 6).Value = "=today()"
Cells(y, 6).Value = "=today()"
Else
y = y + 1
End If
Loop
x = x + 1
y = x + 1
Loop
Application.StatusBar = False
End Sub
Sub deleteBlankCells()`this is to delete unnecessary cells after run the above macro`
Range(Cells(5, 1), Cells(Rows.Count, 1).End(xlUp)).Select
For i = Selection.Rows.Count To 1 Step -1
Application.StatusBar = "OOH! I'm cleaning all the blanks for you....."
If WorksheetFunction.CountA(Selection.Rows(i)) = 0 Then
Selection.Rows(i).EntireRow.Delete
End If
Next i
Application.StatusBar = False
End Sub

I like to work with arrays within VBA, so here is an example.
Assume the data represents the currentregion around A1, but that is easily changed
Read the source data into an array
Check each item in column one to ensure it is unique (countif of that item = 1)
If unique, add the corresponding row number to a Collection
Use the size of th collection and the number of columns to Dim a results array.
Cycle through the collection, writing the corresponding rows to a results array.
Write the results array to the worksheet.
As written, the results are placed to the right of the source data, but could also replace it, or be placed on a different sheet.
Option Explicit
Sub RemoveDuplicatedRows()
Dim vSrc As Variant, vRes() As Variant
Dim rSrc As Range, rRes As Range
Dim colUniqueRows As Collection
Dim I As Long, J As Long
'assume data starts in A1 and represented by currentregion
Set rSrc = Range("a1").CurrentRegion
vSrc = rSrc
Set rRes = rSrc.Offset(0, UBound(vSrc, 2) + 2)
'get collection of non-duplicated rows
Set colUniqueRows = New Collection
For I = 1 To UBound(vSrc)
If WorksheetFunction.CountIf(rSrc.Columns(1), vSrc(I, 1)) = 1 Then _
colUniqueRows.Add I
Next I
'Make up results array
ReDim vRes(1 To colUniqueRows.Count, 1 To UBound(vSrc, 2))
For I = 1 To UBound(vRes, 1)
For J = 1 To UBound(vSrc, 2)
vRes(I, J) = vSrc(colUniqueRows(I), J)
Next J
Next I
rRes.EntireColumn.Clear
rRes.Resize(UBound(vRes)) = vRes
End Sub

Related

VBA: "Run-time error '457':This key is already associated with an element of this collection"

I am having trouble writing a macro for comparing multiple columns in multiple sheets (of same excel file). I wrote few but they were taking so long that excel was crashing.
Let's say I have 4 sheets in one same file.
Sheet1 with two columns (B and C) and 7000 rows.
Sheet2 empty sheet new entries.
Sheet3 empty sheet for old entries but with some updated value/info.
Sheet4 is a database with 2 columns (A and B) and 22000 rows.
I need to compare Column A from Sheet1 to Column B in Sheet4.
If there are completely new entries in Column A sheet1, then copy that entry from Column A sheet1 (and its respective value from Column B sheet1) to a new row (columns A and B) in Sheet2.
If there are entries in Column A Sheet1 that are already in Column A sheet4, then compare their respective Column B values. If column A+column B combo from Sheet 1 is in Sheet4 then ignore it. If a Value from Column A Sheet1 is in Column A Sheet4, but their respective Column B values are not matching then copy Column A+Column B from Sheet1 to new row (columns A and B) in Sheet3.
I hope it is clear enough. Due to amount of rows (7000 in Sheet1 to be compared to 20000 in Sheet4) I cannot write a macro that processes everything under a minute.
Any help ?
Edit 1: I used the code suggested by #FaneDuru (Thank You!). but I am encountering an error: "Run-time error '457':This key is already associated with an element of this collection"
Is it because I have many repeating values in same columns ?
Edit 2: It seems like "if not dict3.exists" code is not recognized by VBA. When I type ".exists" with smaller letter and jump to another line it is supposed correct it to capital ".Exists", right? It is not doing it.
Edit 3: I did some more testing. I was putting breaks and running the code. When I put the break on this line "If WorksheetFunction.CountIf(rngA4, arr1(i, 1)) > 0 Then", no error happens. When I put the break on one line below "For j = UBound(arr4) To 1 Step -1", the error is happening.
Error is : "Run-time error '457':This key is already associated with an element of this collection"
Private Sub CommandButton1_Click()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.EnableEvents = False
Application.DisplayAlerts = False
Dim arr1, arr2, arr3, arr4, dict2 As Object, dict3 As Object, rngA4 As Range
Dim rngB4 As Range, i As Long, j As Long, lastR1 As Long, lastR4 As Long
lastR1 = Sheet1.Range("A" & Sheet1.Rows.Count).End(xlUp).Row
lastR4 = Sheet4.Range("A" & Sheet4.Rows.Count).End(xlUp).Row
Set rngA4 = Sheet4.Range("A2:A" & lastR4)
Set rngB4 = Sheet4.Range("B2:B" & lastR4)
arr1 = Sheet1.Range("B2:C" & lastR1).Value
arr4 = Sheet4.Range("A2:B" & lastR4).Value
Set dict2 = CreateObject("Scripting.Dictionary")
Set dict3 = CreateObject("Scripting.Dictionary")
For i = UBound(arr1) To 1 Step -1
If WorksheetFunction.CountIf(rngB4, arr1(i, 1)) = 0 Then
dict2.Add arr1(i, 1), arr1(i, 2):
End If
If WorksheetFunction.CountIf(rngA4, arr1(i, 1)) > 0 Then
For j = UBound(arr4) To 1 Step -1
If arr1(i, 1) = arr4(j, 1) Then
If arr1(i, 2) <> arr4(j, 2) Then
If arr1(i, 2) <> arr4(j, 2) Then
dict3.Add arr1(i, 1), arr1(i, 2): Exit For
End If
End If
Next j
End If
Next i
If dict2.Count > 0 Then
arr2 = Application.Transpose(Array(dict2.keys, dict2.Items))
Sheet2.Range("A2").Resize(dict2.Count, 2).Value = arr2
End If
If dict3.Count > 0 Then
arr3 = Application.Transpose(Array(dict3.keys, dict3.Items))
Sheet3.Range("A2").Resize(dict3.Count, 2).Value = arr3
End If
MsgBox "Done!"
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.EnableEvents = True
Application.DisplayAlerts = True
End Sub
You can use the excel formula countif to find any entry of data that doesn't exist in your dataset.
Then you can copy the value with Sheets().Range().Value = Sheets().Range().Value in the sheet where you want your output. If the output range is already populated you can use Sheets().Range().End(xlDown).Address to find the address of the last row of your output dataset.
You iterate through every countif values that return a 0 to get all the missing data.
Please, test the next code. You did not answer the clarification questions and the code assumes that there are not more than one occurrence and the processed sheets are loaded by adding rows. The code works independent of this aspect, but if the above assumption is correct, it will run faster:
Sub testProcessNewEntries()
Dim sh1 As Worksheet, sh2 As Worksheet, sh3 As Worksheet, sh4 As Worksheet
Dim arr1, arr2, arr3, arr4, dict2 As Object, dict3 As Object, rngA4 As Range
Dim rngB4 As Range, i As Long, j As Long, lastR1 As Long, lastR4 As Long
Set sh1 = Worksheets("Sheet1") 'use here your first sheet
Set sh2 = Worksheets("Sheet2") 'use here your second sheet
Set sh3 = Worksheets("Sheet3") 'use here your third sheet
Set sh4 = Worksheets("Sheet4") 'use here your fourth sheet
lastR1 = sh1.Range("A" & sh1.Rows.count).End(xlUp).row
lastR4 = sh4.Range("A" & sh4.Rows.count).End(xlUp).row
Set rngA4 = sh4.Range("A2:A" & lastR4)
Set rngB4 = sh4.Range("B2:B" & lastR4)
arr1 = sh1.Range("A2:B" & lastR1).Value
arr4 = sh4.Range("A2:B" & lastR4).Value
Set dict2 = CreateObject("Scripting.Dictionary")
Set dict3 = CreateObject("Scripting.Dictionary")
For i = UBound(arr1) To 1 Step -1
If WorksheetFunction.CountIf(rngB4, arr1(i, 1)) = 0 Then
dict2.Add arr1(i, 1), arr1(i, 2):
End If
If WorksheetFunction.CountIf(rngA4, arr1(i, 1)) > 0 Then
For j = UBound(arr4) To 1 Step -1
If arr1(i, 1) = arr4(j, 1) Then
If arr1(i, 2) <> arr4(j, 2) Then
If Not dict3.Exists(arr1(i, 1)) Then
dict3.Add arr1(i, 1), arr1(i, 2): Exit For
End If
End If
End If
Next j
End If
Next i
If dict2.count > 0 Then
arr2 = Application.Transpose(Array(dict2.Keys, dict2.Items))
sh2.Range("A2").Resize(dict2.count, 2).Value = arr2
End If
If dict3.count > 0 Then
arr3 = Application.Transpose(Array(dict3.Keys, dict3.Items))
sh3.Range("A2").Resize(dict3.count, 2).Value = arr3
End If
MsgBox "Ready..."
End Sub

Auto scheduling

I am trying to make an auto scheduling program with an excel.
For example, each number is certain job assigned to the person given day.
1/2 1/3 1/4 1/5
Tom 1 2 2 ?
Justin 2 3 1 ?
Mary 3 3 ?
Sam 1 ?
Check O O X ? ## check is like =if(b2=c2,"O","X")
The things I want to make sure is every person is given a different job from yesterday.
My idea
while
randomly distribute jobs for 1/5
wend CheckCell = "O"
But I found that checking cell in the vba script doesn't work - the cell is not updated in each while loop.
Could you give me a little pointer for these kinds of program? Because I am new to vbaScript, any kinds of help would be appreciated.
Using VBA, I'm sure there are better ways to do this, but this will check the values from the penultimate column against values from last column and if they match it will write "O" to under the last column, else it will write "X":
Sub foo()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set your worksheet, amend as required
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'get the last row with data on Column A
LastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
counter = 0 'set counter
For i = 2 To LastRow 'loop through penultimate column and add values to array
If ws.Cells(i, LastCol - 1).Value <> "" Then
Values = Values & ws.Cells(i, LastCol - 1) & ","
End If
Next i
Values = Left(Values, Len(Values) - 1)
Values = Split(Values, ",") 'split values into array
For i = 2 To LastRow 'loop through last column and add values to array
If ws.Cells(i, LastCol).Value <> "" Then
ValuesCheck = ValuesCheck & ws.Cells(i, LastCol) & ","
End If
Next i
ValuesCheck = Left(ValuesCheck, Len(ValuesCheck) - 1)
ValuesCheck = Split(ValuesCheck, ",")
For y = LBound(Values) To UBound(Values) 'loop through both arrays to find all values match
For x = LBound(ValuesCheck) To UBound(ValuesCheck)
If Values(y) = ValuesCheck(x) Then counter = counter + 1
Next x
Next y
If counter = UBound(Values) + 1 Then 'if values match
ws.Cells(LastRow + 1, LastCol).Value = "O"
Else 'else write X
ws.Cells(LastRow + 1, LastCol).Value = "X"
End If
End Sub
just to clarify are you looking to implement the random number in the vba or the check.
To do the check the best way would be to set the area as a range and then check each using the cells(r,c) code, like below
Sub checker()
Dim rng As Range
Dim r As Integer, c As Integer
Set rng = Selection
For r = 1 To rng.Rows.Count
For c = 1 To rng.Columns.Count
If rng.Cells(r, c) = rng.Cells(r, c + 1) Then
rng.Cells(r, c).Interior.Color = RGB(255, 0, 0)
End If
Next c
Next r
End Sub
this macro with check the text you have selected for the issue and change the cell red if it matches the value to the right.
To make it work for you change set rng = selection to your range and change the rng.Cells(r, c).Interior.Color = RGB(255, 0, 0) to the action you want
A sligthly different approach than the other answers.
Add this function:
Function PickJob(AvailableJobs As String, AvoidJob As String)
Dim MaxTries As Integer
Dim RandomJob As String
Dim Jobs() As String
Jobs = Split(AvailableJobs, ",")
MaxTries = 100
Do
MaxTries = MaxTries - 1
If MaxTries = 0 Then
MsgBox "Could find fitting job"
End
End If
RandomJob = Jobs(Int((1 + UBound(Jobs)) * Rnd()))
Loop Until RandomJob <> AvoidJob
PickJob = RandomJob
End Function
And put this formula in your sheet
=PickJob("1,2,3",D2)
where D2 points to is the previous job

Excel VBA script to transfer rows from one worksheet to another based on a certain value

I am a novice when it comes to Excel VBA and Macros. I have a workbook that contains two primary sheets - "DAILY_SHOP_FILE" and "Reconciled", the former serves as an order sheet and the latter serves as an archive sheet for the orders once they have been shipped. I want to write a VBA Script/Macro that transfers an entire row from the DAILY_SHOP_FILE to the Reconciled sheet when a user inputs the value "yes" into the final column. Both sheets will have the same headers in row 1. I found a code on here and modified it slightly to my needs:
Dim keyColumn As Integer
Dim i As Integer
Dim keyWord As Variant 'I've used variant, so you can choose your own data type for the keyword
Dim dataSh As String 'I'm using sheet names for sheet referencing
Dim populateSh As String
Dim rowNum As Integer
Dim dataRow() As Variant
Sub Populate()
'set the column number, which contains the keywords, the keyword itself,
'name of the sheet to populate and the row offset you'd like to start populating
populateSh = "Reconciled"
keyColumn = 15
keyWord = "yes"
rowNum = 1
'assuming you run the macro in the sheet you get the data from, get its name to return to it after copying the row
dataSh = ActiveSheet.Name
'loop through all the used cells in the column
For i = 1 To ActiveSheet.UsedRange.Rows.Count
If Cells(i, keyColumn) = keyWord Then
'starting in row 1 in the sheet you populate, you'll have to set the rowNum variable to desired offset few lines above
rowNum = rowNum + 1
Call copyRow(i, rowNum)
End If
Next i
End Sub
Sub copyRow(ByVal cRow As Integer, ByVal pRow As Integer)
Dim colNum As Integer
'set the number of columns you'd like to copy
colNum = 15
'redimension the array to carry the data to other sheet
'this can be done any way you,d like, but I'm using array for flexibility
ReDim dataRow(1 To colNum)
'put the data into the array, as an example I'm using columns 1-15 while skipping the keyword column.
dataRow(1) = Cells(cRow, 1)
dataRow(2) = Cells(cRow, 2)
dataRow(3) = Cells(cRow, 3)
dataRow(4) = Cells(cRow, 4)
dataRow(5) = Cells(cRow, 5)
dataRow(6) = Cells(cRow, 6)
dataRow(7) = Cells(cRow, 7)
dataRow(8) = Cells(cRow, 8)
dataRow(9) = Cells(cRow, 9)
dataRow(10) = Cells(cRow, 10)
dataRow(11) = Cells(cRow, 11)
dataRow(12) = Cells(cRow, 12)
dataRow(13) = Cells(cRow, 13)
dataRow(14) = Cells(cRow, 14)
dataRow(15) = Cells(cRow, 15)
Sheets(populateSh).Select
For p = 1 To UBound(dataRow)
Cells(pRow, p) = dataRow(p)
Next p
Sheets(dataSh).Select
End Sub
It works well but the only problem is it doesn't actually delete the row from the DAILY_SHOP_FILE. How could I solve this? Additionally, it'd be nice to refer to the sheetnames as per the VBA rather than the actual tab names because if a user renamed one of the tabs the code wouldn't work anymore. Thank You!
Sub Update_Reconciled()
Application.ScreenUpdating = False
Dim T2()
Set D1 = CreateObject("scripting.dictionary")
Set R1 = Sheet1.UsedRange 'update Sheet1 to match DAILY_SHOP_FILE code name
T1 = R1
a = 1
For i = 2 To UBound(T1)
If Trim(UCase(T1(i, UBound(T1, 2)))) = "YES" Then
D1(i) = i
ReDim Preserve T2(1 To UBound(T1, 2), 1 To a)
For j = 1 To UBound(T1, 2)
T2(j, a) = T1(i, j)
Next j
a = a + 1
End If
Next i
If a > 1 Then
Sheet2.Range("A99999").End(xlUp).Offset(1, 0).Resize(UBound(T2, 2), UBound(T2, 1)) = Application.Transpose(T2) 'update Sheet2 to match Reconciled code name
cnt = 0
For Each k In D1.items
Sheet1.Rows(k - cnt).Delete 'update Sheet1 to match DAILY_SHOP_FILE code name
cnt = cnt + 1
Next k
End If
Application.ScreenUpdating = True
End Sub
Sorry for not looking at your specific setup, but here is a generic solution that should work fine for you, with just a bit of customization. This is general enough to help others as well.
Sub NewSheetData()
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Dim Rng As Range
Set Rng = Range([A1], Range("A" & Rows.Count).End(xlUp))
On Error Resume Next
With Rng
.AutoFilter , field:=1, Criteria1:="network", Operator:=xlOr, Criteria2:="telcom"
.SpecialCells(xlCellTypeVisible).EntireRow.Copy Sheets("Sheet2").Range("A1")
.AutoFilter
End With
On Error GoTo 0
Application.EnableEvents = True
End Sub

Need help improving my VBA loop

I have an Excel Worksheet consisting of two columns, one of which is filled with strings and the other is emtpy. I would like to use VBA to assign the value of the cells in the empty column based on the value of the adjacent string in the other column.
I have the following code:
Dim regexAdmin As Object
Set regexAdmin = CreateObject("VBScript.RegExp")
regexAdmin.IgnoreCase = True
regexAdmin.Pattern = "Admin"
Dim i As Integer
For i = 1 To 10 'let's say there is 10 rows
Dim j As Integer
For j = 1 To 2
If regexAdmin.test(Cells(i, j).Value) Then
Cells(i, j + 1).Value = "Exploitation"
End If
Next j
Next i
The problem is that when using this loop for a big amount of data, it takes way too long to work and, most of the time, it simply crashes Excel.
Anyone knows a better way to this?
You have an unnecessary loop, where you test the just completed column (j) too. Dropping that should improve the speed by 10-50%
Dim regexAdmin As Object
Set regexAdmin = CreateObject("VBScript.RegExp")
regexAdmin.IgnoreCase = True
regexAdmin.Pattern = "Admin"
Dim i As Integer
For i = 1 To 10 'let's say there is 10 rows
If regexAdmin.test(Cells(i, 1).Value) Then
Cells(i, 1).offset(0,1).Value = "Exploitation"
End If
Next i
If the regex pattern really is simply "Admin", then you could also just use a worksheet formula for this, instead of writing a macro. The formula, which you'd place next to the text column (assuming your string/num col is A) would be:
=IF(NOT(ISERR(FIND("Admin",A1))),"Exploitation","")
In general, if it can be done with a formula, then you'd be better off doing it so. it's easier to maintain.
Try this:
Public Sub ProcessUsers()
Dim regexAdmin As Object
Set regexAdmin = CreateObject("VBScript.RegExp")
regexAdmin.IgnoreCase = True
regexAdmin.Pattern = "Admin"
Dim r As Range, N As Integer, i As Integer
Set r = Range("A1") '1st row is headers
N = CountRows(r) - 1 'Count data rows
Dim inputs() As Variant, outputs() As Variant
inputs = r.Offset(1, 0).Resize(N, 1) ' Get all rows and 1 columns
ReDim outputs(1 To N, 1 To 1)
For i = 1 To N
If regexAdmin.test(inputs(i, 1)) Then
outputs(i, 1) = "Exploitation"
End If
Next i
'Output values
r.Offset(1, 1).Resize(N, 1).Value = outputs
End Sub
Public Function CountRows(ByRef r As Range) As Long
If IsEmpty(r) Then
CountRows = 0
ElseIf IsEmpty(r.Offset(1, 0)) Then
CountRows = 1
Else
CountRows = r.Worksheet.Range(r, r.End(xlDown)).Rows.Count
End If
End Function

Inefficient code that doesn't find matching data values

I have 3 issues with the following piece of code:
Intention of code: I have a table of data, 4 columns (F,G, H and I) wide and X rows long (X is typically between 5 and 400). I have a list of dates in column M, typically no more than 8 dates. Column H of table, contains dates as well. I want to find the dates that are in both columns (H and M) and whenever they appear, go to the same row in column I and set its value to zero, and the one after it (so if a match was in H100, then I100 and I101 would be zeroed).
issues with code: edited 1) as per feedback.
1) I have, using an if formula (=if(H100=M12,1,0), verified that there is one match, as how the spreadsheet sees it. The macro does not find this match, despite confirmation from the if formula. Cells I100 and I101 have nonzero values, when they should be zeroed.
2) the code runs, but takes about 3 minutes to go through 3 sheets of 180 rows of data. What can be done to make it run faster and more efficiently? It could have up to 30 sheets of data, and 400 rows (extreme example but possible, in this instance im happy to let it run a bit).
3) Assuming my data table before the macro is run, is 100 rows long, starting in row 12, after the macro, column I has nonzero values for 111 rows, and zeroes for the next 389. Is there a way I can prevent it from filling down zeroes, and leaving it blank?
I am using a correlate function afterwards on column I and there huge agreement of 0's with 0's is distorting this significantly. Thanks in advance,
Sub DeleteCells()
Dim ws As Worksheet
Dim cell As Range, search_cell As Range
Dim i As Long
Dim h As Long
Application.ScreenUpdating = False
For Each ws In ThisWorkbook.Worksheets
If Not ws.Name = "Cover" Then
For Each cell In ws.Range("H12:H500")
On Error Resume Next
h = ws.Range("G" & Rows.Count).End(xlUp).Row
i = ws.Range("L" & Rows.Count).End(xlUp).Row
Set search_cell = ws.Range("M12:M" & h).Find(what:=cell.Value, LookIn:=xlValues, lookat:=xlWhole)
On Error GoTo 0
If Not search_cell Is Nothing Then
ws.Range("I" & cell.Row).Value = 0
ws.Range("I" & cell.Row + 1).Value = 0
Set search_cell = Nothing
End If
Next cell
End If
Next ws
Application.ScreenUpdating = True
Set ws = Nothing: Set cell = Nothing: Set search_cell = Nothing
End Sub
EDIT: TESTED CODE, will work for 0, 1 row of data in H/M column starting from row 12?
EDIT: Updated the cell to handle case with 1 line of data, untested :|
I will give my solution first, this one should be much faster because it read the cells into memory first
Please comment if it doesn't work or you have further question
Sub DeleteCells()
Dim ws As Worksheet
Dim i As Long
Dim h As Long
Dim MColumn As Variant ' for convinence
Dim HColumn As Variant
Dim IColumn As Variant
Application.ScreenUpdating = False
For Each ws In ThisWorkbook.Worksheets
If Not ws.Name = "Cover" Then 'matching the target sheet
' matching the rows where column M's date matches column H's date
'starting row num is 12
With ws ' for simplifying the code
h = .Range("H" & .Rows.count).End(xlUp).Row
If h = 12 Then ' CASE for 1 row only
If Range("H12").Value = Range("M12").Value Then
Range("I12:I13").Value = ""
End If
ElseIf h < 12 Then
' do nothing
Else
ReDim HColumn(1 To h - 11, 1 To 1)
ReDim MColumn(1 To h - 11, 1 To 1)
ReDim IColumn(1 To h - 10, 1 To 1)
' copying the data from worksheet into 2D arrays
HColumn = .Range("H12:H" & h).Value
MColumn = .Range("M12:M" & h).Value
IColumn = .Range("I12:I" & h + 1).Value
For i = LBound(HColumn, 1) To UBound(HColumn, 1)
If Not IsEmpty(HColumn(i, 1)) And Not IsEmpty(MColumn(i, 1)) Then
If HColumn(i, 1) = MColumn(i, 1) Then
IColumn(i, 1) = ""
IColumn(i + 1, 1) = ""
End If
End If
Next i
'assigning back to worksheet cells
.Range("H12:H" & h).Value = HColumn
.Range("M12:M" & h).Value = MColumn
.Range("I12:I" & h + 1).Value = IColumn
End If
End With
End If
Next ws
Application.ScreenUpdating = True
End Sub