In this project, I am looking to delete duplicates based on the ID number by keeping the latest entries. Additionally, I want to keep every cell in Column D and onward from the previous entries. This ultimately means that the latest entries will be replaced in the previous entries’ row. Please see tables below for more clarity:
Based on the example given above, the result I am looking for is to:
Delete duplicates based on the ID from columns A to C and keep the latest entries
Keep Columns D to H from the previous entries
Replace previous entries by the latest ones in the previous entries’ row.
In other words: Update Columns A to C without modifying Columns D to H
So, the initial code that I had was as follow. It only kept the previous entries and kept columns D to H:
Sub Delete_Duplicates()
Sheet5.Range("$A$1:$H$29999").RemoveDuplicates Columns:=Array(1) _
, Header:=xlYes
End Sub
The table below shows what i would obtain:
The next code I did was to keep the newest entries, but this deletes my entries in column D to H:
Sub Delete_Duplicates_2()
Dim Rng As Range, Dn As Range, n As Long
Dim Lst As Long, nRng As Range
Set Rng = Sheet5.Range("$A$2:$H$29999")
Lst = Range("A" & Rows.Count).End(xlUp).Row
With CreateObject("scripting.dictionary")
.CompareMode = vbTextCompare
For n = Lst To 1 Step -1
If Not .Exists(Range("A" & n).Value) Then
.Add Range("A" & n).Value, Nothing
Else
If nRng Is Nothing Then
Set nRng = Range("A" & n)
Else
Set nRng = Union(nRng, Range("A" & n))
End If
End If
Next n
If Not nRng Is Nothing Then
nRng.EntireRow.Delete
End With
End Sub
The table below shows what I would obtain:
I am open to any suggestions and thank you for your help!
Try this solution - since you're essentially working with a string in your date column, we have to split out the number and test to see if it's greater or less than the other week's number:
Option Explicit
Sub Delete_Duplicates()
Dim i As Long, j As Long
Dim id As String, weeknum As Long
For i = Cells(Rows.Count, 1).End(xlUp).Row To 2 Step -1
id = Cells(i, 1).Value
weeknum = Split(Cells(i, 3).Value, " ")(1)
For j = i - 1 To 2 Step -1
If Cells(j, 1).Value = id Then
If Split(Cells(j, 3).Value, " ")(1) < weeknum Then
Rows(j).Delete
i = i - 1
Else
Rows(i).Delete
Exit For
End If
End If
Next j
Next i
End Sub
Related
[Copy A2 to E2 till the end of row of the table and check if the cell is within the same month](https://i.stack.imgur.com/Q7YAx.png)
Hi,
I would like to loop through rows from a sheet table from column A2 to E2 to A3 to E3... till the end of the table Ai to Ei by defining a variable and counting the last row of the table.
As the second step, I would like to copy the cells into another sheet and fill it the corresponding months.
[Desired Output--> it will copy the data and return to another sheet in the corresponding month] (https://i.stack.imgur.com/zhgYh.png)
Instead, I've changed the data type into a number format and have set up two condition to loop through.
eg. 1/1/2017 change to 42736
28/2/2017 change to 42794
Sub Mike_Copy_cell()
Dim i As Long 'for looping inside each cell
Dim myvalue As Variant
Dim Lastrow As Long
Const StartRow As Byte = 2
Dim LastMonth As Long
("Mike Filter").Select
Lastrow = Range("A" & StartRow).End(xlDown).Row
For i = StartRow To Lastrow
myvalue = Range("H" & i).Value
If myvalue \< Sheets("Automate Report").Range("A" & i).Value \_
'First data Feb Data 42794 \< Jan Category 42736
Then Sheets("Automate Report").Range("B" & i).Value = ""
'leave the cells in blanks and loop through next cell
If myvalue > Sheets("Automate Report").Range("A" & i).Value _
'First data Feb Data 42794 > Jan Category 42736
Then Range("A" & i, "E" & i).Copy Sheets("Automate Report").Range("B" & i, "F" & i)
'Copy the cells into corresponding category
Next i
End sub()
In my output, it is able to loop through and copy all the cells. However, I am wondering the reason why VBA output is not able leave any blank cells when the first condition is met ?
**I am expecting some blanks in the table if it is not data is not within the same month or in my case is less than criteria I have set. **
The output of my code
If myvalue < Sheets("Automate Report").Range("A" & i).Value _
Then Sheets("Automate Report").Range("B" & i).Value = ""
Greatly appreciate if you can advise the flaws in my code. Massive Thanks.
Best regards,
Kenneth
I'll try to help. But before, may I give you two suggestions that might help you?
First, for me the best way to find the last row is, instead of using xldown from the first row, using xlup from the very last row of excel. This way, if there is a blank in any middle row, the code still gives you the last row with value.
Second, I found that referring to any cells with the "range" method may limit you sometimes when using variables in this reference. I think using the "cells(row, column)" method is more useful.
Why not trying this?
Lastrow = Cells(Rows.Count, 1).End(xlUp).Row
Sorry for the suggestions, It's just that I wish someone had taught them to me sooner.
Back to the topic, I think the problem is how you structure the "if" statement. Allow me to change it a bit:
Lastrow = Cells(Rows.Count, 1).End(xlUp).Row
For i = StartRow To Lastrow
myvalue = cells(i, 8).Value
'if myvalue date is equal or previous to the one found in Ai...
If myvalue <= Sheets("Automate Report").cells(i, 1).Value then
Sheets("Automate Report").cells(i, 2).Value = ""
'but if myvalue is later than Ai...
else
sheets("Automate Report").select
range(cells(i, 1), cells(i, 5).select
selection.copy
cells(i, 2).select
activesheet.paste
end if
Next i
Hope this helps. Best regards,
Mike
I'm not sure what your code is doing but consider using an array(12) of row numbers, one for each month. Copy lines into corresponding month and increment the row number for that month. For example ;
Option Explicit
Sub Mike_Copy_cell()
Const LINES_MTH = 5 ' lines per month
Dim wb As Workbook
Dim wsIn As Worksheet, wsOut As Worksheet
Dim lastrow As Long, rIn As Long, rOut(12) As Long
Dim uid As String, prevuid As String
Dim dAVD As Date, m As Long, n As Long
Set wb = ThisWorkbook
Set wsIn = wb.Sheets("Mike Filter")
Set wsOut = wb.Sheets("Automate Report")
' space out months
For n = 0 To 11
rOut(n + 1) = 2 + n * LINES_MTH
wsOut.Cells(rOut(n + 1), "A").Value2 = MonthName(n + 1)
Next
n = 0
With wsIn
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For rIn = 2 To lastrow
dAVD = .Cells(rIn, "D")
' create a unique ID to skip duplicates
uid = .Cells(rIn, "A") & Format(.Cells(rIn, "D"), "YYYY-MM-DD")
If uid <> prevuid Then
m = Month(dAVD)
.Cells(rIn, "A").Resize(, 5).Copy wsOut.Cells(rOut(m), "B")
rOut(m) = rOut(m) + 1
n = n + 1
End If
prevuid = uid
Next
End With
MsgBox n & " lines copied to " & wsOut.Name, vbInformation
End Sub
Real project sample here: http://s000.tinyupload.com/?file_id=06911274635715855845
Sample here
its all in the title,
Lets say i got a doc with ten columns and three hundred rows, A and B contain a number and C to J can contain many words and sometimes the word "Banana".
I'd like to automate a task that goes line by line on the worksheet and deletes the whole row if every cell between C and J contains "Banana", ignoring A and B.
Usually when i have such a question i submit my ideas but i'm quite stumped here from the get go.
Would you be kind enough to help?
Try the next code, please. It will delete all rows having the same string in columns C to J ("Banana" inclusive...). It would be very fast. The deletion is done at the end, at once:
Edited:
Since, in an worksheet containing tables, the non contiguous entire rows range deletion is not allowed, I adapted the code to test if such a table is involved, intersect the collected range to be deleted (its EntireRow) with the table and delete the intersected table rows.
Please, test next updated code:
Sub testDeleteRowsSameWord()
Dim sh As Worksheet, lastRow As Long, i As Long, rngDel As Range
Set sh = ActiveSheet ' use here your necessary sheet
lastRow = sh.Range("C" & Rows.Count).End(xlUp).Row
For i = 1 To lastRow
If WorksheetFunction.CountIf(sh.Range("D" & i & ":EA" & i), _
sh.Range("D" & i).Value) = 128 Then
If rngDel Is Nothing Then
Set rngDel = sh.Range("A" & i)
Else
Set rngDel = Union(rngDel, sh.Range("A" & i))
End If
End If
Next i
If Not rngDel Is Nothing Then
If sh.ListObjects.Count > 0 Then
If sh.ListObjects.Count > 1 Then MsgBox _
"This solution works only for a table...": Exit Sub
Dim Tbl As ListObject, rngInt As Range
Set Tbl = sh.ListObjects(1)
Set rngInt = Intersect(Tbl.Range, rngDel.EntireRow)
If rngInt.Count > 0 Then
rngInt.Delete xlUp
Else
rngDel.EntireRow.Delete xlUp
End If
Else
rngDel.EntireRow.Delete xlUp
End If
End If
End Sub
They are infinite ways to achieve what you want.
One for example can be something like :
Dim i As Integer, j As Integer
Dim mBanana As Boolean
For i = 299 To 0 Step -1 'rows 1 to 300
mBanana = True
For j = 0 To 7 'columns C to J
If Sheets("nameofyoursheet").Range("C1").Offset(i, j).Value <> "Banana" Then
mBanana = False
End If
Next j
If mBanana = True Then
Sheets("nameofyoursheet").Range("C1").Offset(i, j).EntireRow.Delete
End If
Next i
Note that the numbers of rows and columns are hardcoded in the parameters of the For, you can easily adapt the code.
I have a set of data in Excel that looks similar to this:
24/01/2020 25/01/2020 26/01/2020 27/01/2020
Item A Item A Item B Item C
Item B Item C Item C Item D
Item C Item D
I can run a formula to ascertain how many times a certain item occurs in the dataRange: =COUNTIF(dataRange,"Item C")
What I am now looking to do is get the date associated with each nth occurrence. Everything I have found online only deals with finding the nth occurrence in a single column, whereas I would like a formula that would tell me that the cell for each occurence in the full range. E.G. 1st occurrence of 'Item C' is in cell A4, and the 2nd occurrence is B3, the third is C3 and the 4th is in cell D2.
Thank you all!
Thanks to #JvdV for the assistance with this. Using the Microsoft Docs I was able to find a combination of Range.Find and FindNext, resulting in the following:
Sub cellAddresses()
With Range("A1:D6")
Set c = .Find("Item A", LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
MsgBox c.Address
Set c = .FindNext(c)
Loop While c.Address <> firstAddress
End If
End With
End Sub
This returns the cell addresses for each occurrence and ensures that once all occurences have been looped through, no further information is fed back.
Thanks again!
You could also try Worksheet Change Event:
Import the Item_Code in Cell G1
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Me.Range("G1")) Is Nothing Then
Dim i As Long, j As Long, Counter As Long, LastRow As Long
Dim ItemCode As String
Counter = 1
With Me
ItemCode = Target.Value
For i = 1 To 4
For j = 2 To .Cells(.Rows.Count, i).End(xlUp).Row
If .Cells(j, i).Value = ItemCode Then
LastRow = .Cells(.Rows.Count, "I").End(xlUp).Row + 1
Application.EnableEvents = False
.Range("I" & LastRow).Value = .Cells(1, i).Value
.Range("J" & LastRow).Value = Counter
.Range("K" & LastRow).Value = .Cells(j, i).Address
Application.EnableEvents = True
Counter = Counter + 1
End If
Next j
Next i
End With
End If
End Sub
I am working with a dataset that is refreshed when a sharepoint survey is completed, and the responses to that survey are then exported to a table in Excel. I want to be able to delete an entire row(s) if the ZIP code (string) of the facility reviewed (Column Y) is the same, but I want to keep the most-recent survey response, or that which appears in the higher row value.
For example, row 38 contains a survey response with a ZIP code string of "33138." Row 52 (survey completed more-recently), was also completed for ZIP code "33138." I want to delete row 38, and retain row 52.
Looking for a VBA solution.
#BigBen I've tried this code, which I found on a few discussion boards. Also note, I plan run this from a button on "Dashboard" tab for records on the "data" tab.
Sub deduplicate()
Dim Rng As Range, Dn As Range, n As Long
Dim Lst As Long, nRng As Range
Lst = Range("Y" & Rows.Count).End(xlUp).Row
With CreateObject("scripting.dictionary")
.CompareMode = vbTextCompare
For n = Lst To 1 Step -1
If Not .Exists(Range("Y" & n).Value) Then
.Add Range("Y" & n).Value, Nothing
Else
If nRng Is Nothing Then
Set nRng = Range("Y" & n)
Else
Set nRng = Union(nRng, Range("Y" & n))
End If
End If
Next n
If Not nRng Is Nothing Then nRng.EntireRow.Delete
End With
End Sub
#BigBen, as part of a longer script, I also tried the following code. It sort of worked, but only removed the first instance of a duplicate, and not all duplicate rows.
Worksheets("Data").Activate
Dim lrow As Long
For lrow = Cells(Rows.Count, "Y").End(xlUp).Row To 2 Step -1
If Cells(lrow, "Y") = Cells(lrow, "Y").Offset(-1, 0) Then
Cells(lrow, "Y").Offset(-1, 0).EntireRow.Delete
End If
Next lrow
Based on your comment that the data is in a table (ListObject), something like this could work. This loops from the first to last row, deleting the row if a CountIf on the column, using the current row's value, is greater than 1.
Sub DedupeZipCodes()
Dim tbl As ListObject: Set tbl = ThisWorkbook.Sheets("Data").ListObjects("Table1")
Dim zipCol As ListColumn: Set zipCol = tbl.ListColumns("Zip Code")
Dim currentRow As Long, lastRow As Long
With zipCol
currentRow = 1
lastRow = .DataBodyRange.Rows.Count
Do While currentRow < lastRow
If Application.CountIf(.DataBodyRange, .DataBodyRange(currentRow).Value) > 1 Then
.DataBodyRange(currentRow).EntireRow.Delete
lastRow = .DataBodyRange.Rows.Count
Else
currentRow = currentRow + 1
End If
Loop
End With
End Sub
I am trying to erase duplicate rows starting from bottom, but it isnt working. It keeps two copies but deletes other duplicate items.
With wb_DST.Sheets(sWs_DST)
lncheckduplicatescolumn = .Cells(.Rows.Count, "A").End(xlUp).row
wb_DST.Sheets(sWs_DST).Range(("A13:A" & lncheckduplicatescolumn - 2 & ":" & "AW13:AW" & lncheckduplicatescolumn - 2)).Sort key1:=wb_DST.Sheets(sWs_DST).Range("A13:A" & lncheckduplicatescolumn - 2), order1:=xlDescending, Header:=xlNo
Dim row As Range
Dim rng As Range
Dim cell As Range
Dim i As Integer
Set rng = wb_DST.Sheets(sWs_DST).Range("A13:A" & lncheckduplicatescolumn - 2)
For Each cell In rng
If cell.Value = cell.Offset(-1, 0).Value Then
.cell.Offset(-1, 0).EntireRow.Delete
End If
Next
End with
If Excel shows
Column A Column B
A 1
A 2
A 3
I want the code to retain the last row, and delete the ones above it.
The result should be
Column A Column B
A 3
Thanks,
Work from the bottom up and loop until all 'higher' (i.e. in a row less than current) are removed.
dim dup as variant, r as long, lncheckduplicatescolumn as long
With wb_DST.Sheets(sWs_DST)
lncheckduplicatescolumn = .Cells(.Rows.Count, "A").End(xlUp).row
for r = lncheckduplicatescolumn to 2 step -1
dup = application.match(.cells(r, "A").value, .columns(1), 0)
if dup < r then .rows(dup).delete
next r
end with
This will take a few more cycles than is absolutely necessary but the operation is efficient enough that it should not make a significant difference.
Dim x as integer
Dim y as string
Dim J as integer
Dim I as integer
x = activesheet.range("A" & Activesheet.range("A1").endxl.down).count 'This will count the total number of rows.
for i = x to 2 'this should count backwards from bottom to top, since you have headers, stop at row 2
y = Activesheet.range("A" & i).value 'places value in a variable
For j = x - i - 1 to 1 'this is another loop, but it should start above the whatever the cell that Y got its value
if activesheet.range("a" & j).value = y then 'comparison
'do what you need to delete the row
end if
Next
Next
I think this will go start at the bottom, put that first value in a variable, and then will go through the rest of the list check the values to see if is compatible. The second for loop might need to be adjusted.
not a pretty answer - but from what it looks like, you should be ending up with the last and first occurrence of the duplicate:
Column A Column B
A 1
A 3
To patch your answer (there are more elegant ways), you could find the last row again after the loop is finished and check for one last duplicate:
For Each cell In rng
If cell.Value = cell.Offset(-1, 0).Value Then
.cell.Offset(-1, 0).EntireRow.Delete
End If
Next
redefine your last row
lncheckduplicatescolumn = .Cells(.Rows.Count, "A").End(xlUp).row
and check for one more duplicate
If Range("A" & lncheckduplicatescolumn).Value = Range("A" & lncheckduplicatescolumn).Offset(-1, 0).Value Then
.cell.Offset(-1, 0).EntireRow.Delete
End If