Excel VBA Remove duplicates in a range - excel

I'm struggling with the updating of a number of sheets that hold master data.
The user can update the register ("TK_Register") with a new item or modify an existing item on the ("EditEX") sheet. Data on the EditEx sheet is stored maintained at C32:P56 and saved on the next empty row of the TK_Register Sheet (Columns A to N)
Using a different code, I can recall all specific rows based on a reference number (stored on EditEX sheet in cells O32:O56 and on the TK_Register sheet in column M).
On running this code,
excel takes all data from EditEx sheet C32:P56
Pastes this data to the next empty row on TK_Register Sheet
Auto filters based on column "N" for "NO" (i.e. don't need to keep this row)
Deletes the rows that where filtered (these are rows that have not been used and contain Default data)
Unfilters the data
This is where I get an issue. This adding all data to the TK_Register sheet includes new Items as well as previous items that have been updated.
As we need to make regular additions, updates and changes, when we need to edit it again we only want to see the most recent line items appear on the EditEx sheet.
The user can then make changes to any of the recalled rows and/or add a new one.
My below code only works where the last row reference number (column M) is duplicated. If more than 1 row is being added, it finds no duplicates.
I know I'm going through this the long way, but any ideas how I can have it search each reference number (column M) being pasted (there will be multiple rows) if found update that row with new data, if not found, add to the next available rows.
Sub SaveUpdatedRec()
Dim rng4 As Range
Set rng4 = Sheets("EditEx").Range("C32:P56")
Sheets("TK_Register").Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(rng4.Rows.Count, rng4.Columns.Count).Cells.Value = rng4.Cells.Value
Sheets("TK_Register").Range("A1:N1000").AutoFilter field:=14, Criteria1:="NO"
Application.DisplayAlerts = False
Sheets("TK_Register").Range("A2:N1000").SpecialCells(xlCellTypeVisible).Delete
Application.DisplayAlerts = True
On Error Resume Next
Sheets("TK_Register").ShowAllData
On Error GoTo 0
Sheets("AI_Register").Select
Range("A1").Select
Dim lrow1 As Long
For lrow1 = Worksheets("AI_Register").Cells(Rows.Count, "M").End(xlUp).Row To 2 Step -1
If Cells(lrow1, "M") = Cells(lrow1, "M").Offset(-1, 0) Then
Cells(lrow1, "M").Offset(-1, 0).EntireRow.Delete
End If
Next lrow1
ActiveWorkbook.RefreshAll
Sheets("EditEx").Select
ActiveWindow.SmallScroll Down:=-120
Range("B13").Select
MsgBox ("Record Updates have been Saved")
End Sub

Below is a sample code using .RemoveDupliates which remove duplicates from column 1 of the range given taking in consideration that the column has header.
Option Explicit
Sub test()
Dim LastroW As Long
With ThisWorkbook.Worksheets("Sheet1")
LastroW = .Cells(.Rows.Count, "A").End(xlUp).Row
.Range("A1:A" & LastroW).RemoveDuplicates Columns:=1, Header:=xlYes
End With
End Sub

Related

VBA in Excel - Copy past values of a range of cells to other cells

Looking for some help,
I have created a command button and attached the following macro:
Private Sub CommandButton1_Click()
Range("J2:J3000").Copy
Range("G2:G3000").PasteSpecial xlPasteValues, xlNone, SkipBlanks
End Sub
The task im doing is very simple, copy values only from cells from range J2:J3000 to G2:G3000 but skip blanks when pasting to the corresponding row cell. (J2 copy, paste to G2) This isnt working as its overriding data in the range G2:G3000 with blanks from J2:J3000 instead of pasting the data only
To give context to the ranges.
J2:J3000 has a function
=IF(ISNA(VLOOKUP(A2,H:H,1,FALSE)),"","Yes")
which is checking data in the sheet that is manually pasted into column H:H and deleted with different data daily.
G2:G3000 has blank text cells where the results from J2:J3000 is then manually pasted to the corresponding row under column G.
(Basically, checking the value returned from the lookup, if it says yes then its manually copied to the cell in column G on the matching row.)
I am trying to introduce a button macro that can paste value returned the lookup and automate this process.
Private Sub CommandButton1_Click()
Range("J2:J3000").Copy
Range("G2:G3000").PasteSpecial xlPasteValues, xlNone, SkipBlanks
End Sub
Your current method is overwriting everything in Column G
To correct this you can work with filtered ranges or utilize loops to conditionally update values in Column G. A loop solution is below:
Sub Test()
'Update the sheet name
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim i As Long
For i = 2 To 3000
If ws.Range("J" & i).Value = "Yes" Then
ws.Range("G" & i).Value = ws.Range("J" & i).Value
End If
Next i
End Sub
For now this is manually hardcoded to stop at row 3,000. It is likely better to change this to be dynamic. To do this you just need to add a new variable (lr for 'last row') to store value of last row and modify the loop to iterate up until lr instead of the hardcoded value 3,000. Relevant bits of code are below
Dim i As Long, lr As Long
lr = ws.Range("J" & ws.Rows.Count).End(xlUp).Row
For i = 2 To lr
'If .......
Next i

Autofilter with multiple variable criterias

I have a sheet which contains a column full of Item IDs called "Werkzeugtabelle Vormontage" and another sheet which contains part of the item IDs listed in sheet 1.
I want to filter Sheet 1 by the Item IDs that are similar to the ones in sheet 2. So basically have the sheet with more IDs chopped to the size of the sheet with less IDs. (Deleting the not similar ones would also be an option but no clue how that might work.)
If CheckSheet("BMV Vormontage") Then
Sheets("Werkzeugtabelle").Select
Sheets("Werkzeugtabelle").Copy After:=Sheets("BMV Vormontage")
ActiveSheet.Name = "Werkzeugtabelle Vormontage"
lRow = Cells(Rows.Count, 1).End(xlUp).Row
Sheets("Restanschluss Vormontage").Select
xRow = Cells(Rows.Count, 11).End(xlUp).Row
'CountUnique ("K3:K100")
'critCount = CountUnique.Count
For i = 3 To lRow
For a = 10 To xRow
Sheets("Werkzeugtabelle Vormontage").Cells(i, 1).AutoFilter Field:=1, Criteria1:=Sheets("Restanschluss Vormontage").Cells(a, 11).Value
Next a
Next i
End If
The CheckSheet is looking for that sheet to get a starting point in the workbook. "Werkzeugtabelle" is the non filtered vanilla sheet.
Whenever I have more than one similar Item ID between the two sheets, it won't show, because I am only looking for one criteria it seems.
I tried to do a loop.
Alright I guess I have found the solution. At least it does everything it does and doesn't spam me with error. Could you guys double check if this is a good code?
Sub Werkzeugtabelle_splitten()
Dim ws As Worksheet
Dim rng As Variant
Set ws = Sheets("Werkzeugtabelle")
' Splitten Vormontage
If CheckSheet("BMV Vormontage") Then
rng = Sheets("Restanschluss Vormontage").Range("K10:K100").Value
ws.Range("A3").AutoFilter _
Field:=1, _
Criteria1:=Application.Transpose(rng), _
Operator:=xlFilterValues
ws.Copy After:=Sheets("BMV Vormontage")
ActiveSheet.Name = "Werkzeugtabelle Vormontage"
ws.ShowAllData
End If
End Sub
So I have made that the orginial "Werkzeugtabelle" sheet will still exist and it only filters it > copies it to the right spot in the workbook and afterwards resets the filter on the original.

Wanting Excel to cut and paste a row of information when criteria is met

I have an excel spread sheet set up for my partner's home business where she can input data relating to people joining the business. I am looking to have the data from that row cut and paste to a separate sheet depending on the criteria in one of the cells. The main sheet is called "Workspace".
If the person on row 6 has agreed to join the business then a "Yes" would be placed in cell V6. Once the Yes has been input I am aiming for the columns A:G to be cut and paste onto the sheet "Joined" as well as the rest of that row being deleted and preferably the rows underneath moving up one (if that is possible). The data would be pasted onto the next blank row on the "Joined" sheet.
On the flip side, if the person on row 6 states they are uninterested then a "Not Interested" would be placed in cell H6. Once the not interested has been input I am aiming for the columns A:G to be cut and paste onto the sheet "Not Interested" as well as the rest of that row being deleted, like above.
Is it also possible to have the spread sheet sort names alphabetically each time a new name is added? The starting row for data is 6.
I hope this all makes sense and really hope someone is able to assist. I am quite good when it comes to formulas but not got a clue where to start with regards to macros.
This is my code so far:
Sub Test()
For Each Cell In Sheets("Workspace").Range("V:V")
If Cell.Value = "Yes" Then
matchRow = Cell.Row
Rows(matchRow & ":" & matchRow).Select
Selection.Copy
Sheets("Joined").Select
ActiveSheet.Rows(matchRow).Select
ActiveSheet.Paste
Sheets("Workspace").Select
End If
Next
End Sub
Here is a good starting point for you. I added comments to the code so you can see what every line does.
This sub searches for "yes" in column V and copies Range A:G of the columns with "yes" into sheet Joined. Then it deletes the entire row where the "yes" was found.
I think from here you can do the second part for "Not Accepted" on your own.
Sub Test()
Dim MatchRow As Long, FirstRow As Long, LastRow As Long
Dim Destination As Range
Dim ws As Worksheet
Set ws = Sheets("Workspace") 'define ws as sheet workspace (shortcut)
FirstRow = 6 'First row with data below headline
LastRow = ws.Cells(ws.Rows.Count, "V").End(xlUp).Row 'Get last used row in column V (so we don't need to go through the full column)
Dim i As Long
i = FirstRow
Do While i <= LastRow 'start searching for "Yes" in FirstRow and end in LastRow
If ws.Range("V" & i).Value = "Yes" Then
MatchRow = ws.Range("V" & i).Row 'remember matched row number
'find last free row in column A of sheet Joined and remember in Destination
With Sheets("Joined")
Set Destination = .Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0)
End With
'Copy range A:G from matched row to destination found above
ws.Range("A" & MatchRow & ":G" & MatchRow).Copy Destination
'Delete copied entire row
ws.Rows(MatchRow).EntireRow.Delete
'reduce LastRow by one (because we deleted one row)
LastRow = LastRow - 1
Else
'go to next row
i = i + 1
End If
Loop
End Sub

copy data based on criteria to another sheet and clear the contents

This code is working to copy the filtered data of "Award" column marked "Yes" to another sheet; however, I'm receiving an error of "Type Mismatch." I'm not 100% now that the code is working properly to filter the data and copy correctly. I currently have 23 rows of test data for proper functionality. If I only put one row of data, then it doesn't copy and paste the data correctly. I am left with the copied 1st row of data plus the 2nd empty row of data. Additionally, it is not clearing the contents of the rows after the paste, so I may add new data as the days progress.
Sub CopySheet()
Dim i As Integer
Dim LastRow As Integer
Dim Search As String
Dim Column As Integer
Sheets("MasterData").Activate
Sheets("MasterData").Range("A1").Select
'Sets an Autofilter to sort out only your Yes rows.
Selection.AutoFilter
'Change Field:=5 to the number of the column with your Y/N.
Sheets("MasterData").Range("$A$1:$G$200000").AutoFilter Field:=7, Criteria1:="Yes"
'Finds the last row
LastRow = Sheets("MasterData").Cells(Sheets("MasterData").Rows.Count, "A").End(xlUp).row
i = 1
'Change the 3 to the number of columns you got in Sheet2
Do While i <= 11
Search = Sheets("ActiveJobStatus").Cells(1, i).Value
Sheets("MasterData").Activate
'Update the Range to cover all your Columns in MasterData.
If IsError(Application.Match(Search, Sheets("MasterData").Range("A1:G1"), 0)) Then
'nothing
Else
Column = Application.Match(Search, Sheets("MasterData").Range("A1:G1"), 0)
Sheets("MasterData").Cells(2, Column).Resize(LastRow, 1).Select
Selection.Copy
Sheets("ActiveJobStatus").Activate
Sheets("ActiveJobStatus").Cells(2, i).Select
ActiveSheet.Paste
End If
i = i + 1
Loop
'Clear all Y/N = Y
'Update the Range to cover all your Columns in MasterData.
Sheets("MasterData").Activate
Column = Application.Match("Award", Sheets("MasterData").Range("A1:F1"), 0)
Sheets("MasterData").Cells(2, Column).Resize(LastRow, 1).Select
Selection.ClearContents
End Sub
Sorry to change your code up so much, but it looks like you might be over-complicating how to do it.
This is some code from a previous question I answered where someone wanted to highlight a specific range whenever the word "Total" was found.
I changed the find to "Yes". Change the SearchRange to your column. (I think G is right).
Also, for future reference, Select should [almost never] be used.
It slows down code execution quite a bit and is not required.
I know the macro recorder likes to use it, but everything can be referenced without using select.
Brief example:
Sheets("ActiveJobStatus").Activate
Sheets("ActiveJobStatus").Cells(2, i).Select
ActiveSheet.Paste
Can Be replaced by:
Sheets("ActiveJobStatus").Cells(2, i).Paste
This code is working to copy the filtered data of "Award" column marked "Yes" to another sheet.
Sub CopyAwardsToActiveJobStatusSheet()
Dim SearchRange, First, Finder As Range
Dim PasteRow as Integer 'Add this to increment the rows we paste your data to
Set SearchRange = Sheets("MasterData").Range("G:G") 'Search This Range for "Yes"
Set Finder = SearchRange.Find("Yes") 'This is what we're looking for
If Finder Is Nothing Then Exit Sub 'We didn't find any "Yes" so we're done
'Drastically increases speed of every macro ever
'(well, when the sheets are modified at least - and it doesn't hurt)
Application.ScreenUpdating = False
First = Finder.Address 'Grab the address of the first "Yes" so we know when to stop
'Get the last row of column "A" on ActiveJobStatusSheet and start pasting below it
PasteRow = Sheets("ActiveJobStatus").Cells(Sheets("ActiveJobStatus").Rows.Count, "A").End(xlUp).Row + 1
Do
'Copy the entire row and paste it into the ActiveJobStatus sheet
'Column A and PasteRow (the next empty row on the sheet)
'You can change these if needed
Finder.EntireRow.Copy Sheets("ActiveJobStatus").Range("A" & PasteRow)
'If you just want A:G, you can use this instead:
'Finder returns the cell that contains "Yes",
'So we offset/resize to get the 6 cells before it and just copy that
'Resize doesn't like negative numbers so we have to combine:
'Finder.Offset(,-6).Resize(,7).Copy Sheets("ActiveJobStatus").Range("A" & PasteRow)
'Look for the next "Yes" after the one we just found
Set Finder = SearchRange.FindNext(after:=Finder)
PasteRow = PasteRow + 1 'Faster than looking for the end again
'Do this until we are back to the first address
Loop While Not Finder Is Nothing And Finder.Address <> First
'Clear MasterData
Sheets("MasterData").Range("A2:G" & Sheets("MasterData").UsedRange.Rows.Count).ClearContents
Application.ScreenUpdating = True 'Drastically increases speed of every macro ever.
End Sub
Just the code:
Sub CopyAwardsToActiveJobStatusSheet()
Dim SearchRange, First, Finder As Range
Dim PasteRow as Integer
Set SearchRange = Sheets("MasterData").Range("G:G")
Set Finder = SearchRange.Find("Yes")
If Finder Is Nothing Then Exit Sub
Application.ScreenUpdating = False
First = Finder.Address
PasteRow = Sheets("ActiveJobStatus").Cells(Sheets("ActiveJobStatus").Rows.Count, "A").End(xlUp).Row + 1
Do
Finder.EntireRow.Copy Sheets("ActiveJobStatus").Range("A" & PasteRow)
Set Finder = SearchRange.FindNext(after:=Finder)
PasteRow = PasteRow + 1
Loop While Not Finder Is Nothing And Finder.Address <> First
Sheets("MasterData").Range("A2:G" & Sheets("MasterData").UsedRange.Rows.Count).ClearContents
Application.ScreenUpdating = True
End Sub
Results:
MasterData Sheet:
ActiveJobStatus Sheet:

Re: Take a value (that is summed) in multiple sheets and insert into a master sheet

Re: Creating a master sheet from multiple sheets.
Multiple sheet description: table with many rows and columns. Columns headings are identical but rows vary. Each sheet is a date.
Task: to take a single value from a specific column (always happens to be column M). the value I want is the total of that column. Take this summed value and insert into a master sheet.
My attempt so far is:
Sub append_master_sheet()
Dim wAppend As Worksheet, wSheet As Worksheet
Dim LastRow As Long
Set wAppend = Worksheets("Master")
For Each wSheet In Worksheets
If wSheet.Name <> wAppend.Name Then
LastRow = WorksheetFunction.Max(3, wAppend.Cells(65536, 2).End(xlUp).Row)
wSheet.UsedRange.Resize(, 13).Copy Destination:=wAppend.Cells(LastRow, 2)
End If
Next wSheet
End Sub
1). it takes all 13 columns rather than only the 13th column. (I see that is because I have set it at 13 as I do not know how to cycle through the preceding columns and skip them to only return the 13th column data (and within this column return the total of the column, not the discrete line items
2) Besides returning all the data which is a problem, it actually consistently skips the final value in the column M.
Can you advise how to amend above code to
1) only return the summed value from column M in the multiple sheets (calendar dates) and insert into master.
thanks,
N
Is this what you are trying (UNTESTED)
Like I mentioned in the comment above, see THIS link on how to find a last row in a column.
I have commented the code so that you will not have a problem understanding it. But if you do, simply post back :)
Note: I am assuming that the last cell in Col M has the SUM
Option Explicit
Sub append_master_sheet()
Dim wAppend As Worksheet, wSheet As Worksheet
Dim wApLRow As Long, wShLRow As Long
Set wAppend = ThisWorkbook.Worksheets("Master")
'~~> Get the last row where the ouput should be placed
wApLRow = wAppend.Range("B" & wAppend.Rows.Count).End(xlUp).Row + 1
For Each wSheet In Worksheets
If wSheet.Name <> wAppend.Name Then
With wSheet
'~~> Fuind the last row in Col M which has the sum
wShLRow = .Range("M" & .Rows.Count).End(xlUp).Row
'~~> Copy over the values to Master Sheet
wAppend.Range("B" & wApLRow).Value = .Range("M" & wShLRow).Value
'~~> Increment the row for next output
wApLRow = wApLRow + 1
End With
End If
Next wSheet
End Sub

Resources