Excel VBA mark duplicate on colA (work on all worksheet include activesheet) - excel

I'd like to mark duplicate on all Worksheet in Workbook. Below the code mark only duplicate if the duplicate exist on other worksheet.
I'd like to mark them also if them exist on Activesheet.
(much better if it possible to mark on different color if duplicate exist only in Activesheet)
Here's a link for solution on similar case, What I need to solve. [a link](https://stackoverflow.com/a/25252503/5493335) "loops through the values of Col A in the sheet which gets activated and then it searches the Col A of all the remaining worksheets and if it finds the ID then it colors the cell background to red. by Siddhart Rout"
I add only one change to this code to eliminate color on empty rows.
But those code is mark(on red color) only if duplicate is one another Worksheet.
I wonder to makr on diffrent color if I found duplicate on activeworksheet.
I will trying to do myself and change the condition with else but It doesn't work. Could anybody get me some help to solve that issue.
Thanks in advance.
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim lRow As Long, wsLRow As Long, i As Long
Dim aCell As Range
Dim ws As Worksheet
Dim strSearch As String
With Sh
'~~> Get last row in Col A of the sheet
'~~> which got activated
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Remove existing Color from the column
'~~> This is to cater for any deletions in the
'~~> other sheets so that cells can be re-colored
.Columns(1).Interior.ColorIndex = xlNone
'~~> Loop through the cells of the sheet which
'~~> got activated
For i = 1 To lRow
'~~> Store the ID in a variable
strSearch = .Range("A" & i).Value
if strSearch <> "" then 'eliminated color empty cell
'~~> loop through the worksheets in the workbook
For Each ws In ThisWorkbook.Worksheets
'~~> This is to ensure that it doesn't
'~~> search itself
If ws.Name <> Sh.Name Then
'~~> Get last row in Col A of the sheet
wsLRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
'~~> Use .Find to quick check for the duplicate
Set aCell = ws.Range("A1:A" & wsLRow).Find(What:=strSearch, _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
'~~> If found then color the cell red and exit the loop
'~~> No point searching rest of the sheets
If Not aCell Is Nothing Then
Sh.Range("A" & i).Interior.ColorIndex = 3
Exit For
End If
End If
Next ws
End if
Next i
End With
End Sub

I'd go with the following refactoring of your code:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim IDsRng As Range, IDCell As Range
Dim ws As Worksheet
Dim strSearch As String
Dim foundInOtherSheet As Boolean, foundInActiveSheet As Boolean
With Sh
Set IDsRng = .Range("A1", .Cells(.Rows.count, 1).End(xlUp)) '<--| set the IDs range as all column A not empty cells with some "text" content
'~~> Remove existing Color from the column
'~~> This is to cater for any deletions in the other sheets so that cells can be re-colored
.Columns(1).Interior.ColorIndex = xlNone
End With
For Each IDCell In IDsRng '<--| Loop through ID cells (i.e. column A "text" cells of the activated sheet)
'~~> Store the ID in a variable
strSearch = IDCell.Value
foundInActiveSheet = WorksheetFunction.CountIf(IDsRng, strSearch) > 1 '<--| count possible dupes in active sheet
foundInOtherSheet = False '<--| initialize it at every new ID
'~~> loop through the worksheets in the workbook
For Each ws In ThisWorkbook.Worksheets
'~~> This is to ensure that it doesn't search itself
If ws.Name <> Sh.Name Then
With ws
foundInOtherSheet = WorksheetFunction.CountIf(.Range("A1", .Cells(.Rows.count, 1).End(xlUp)), strSearch) > 1
If foundInOtherSheet Then Exit For '~~> If found then color then no point searching rest of the sheets
End With
End If
Next
Select Case True '<--| now act accordingly to where duplicates have been found
Case foundInOtherSheet And Not foundInActiveSheet '<--| if duplicates found in "other" sheets only
IDCell.Interior.ColorIndex = 3 '<--| red
Case foundInOtherSheet And foundInActiveSheet '<--| if duplicates found in "other" sheets and in "active" one too
IDCell.Interior.ColorIndex = 6 '<--| yellow
Case Not foundInOtherSheet And foundInActiveSheet '<--| if duplicates found in "active" sheets only
IDCell.Interior.ColorIndex = 14 '<--| green
End Select
Next
End Sub

remove the If ws.Name <> Sh.Name Then line and end if underneath in line with it.

Related

Copying cell values from one sheet to another, and paste it near a cell with specific value

I have a constant task at work where I need to copy a list of numbers to another sheet. In that sheet, I need to paste those numbers one by one, in a cell to the right of cells with a certain value(that repeats in a column). (notice that the target table is sorted by that value -"מודל תגובה" and there are hidden rows.
It's hard to explain so I hope the images will do.
I tried to write suitable code but I kept getting different errors.
It seems that problems occur when copying the cell values to the target cells.
Dim i As Integer
i = 4
Do While IsEmpty(Cells(i, 1).Value) = False
Worksheets(1).Select
Cells(i, 1).Copy
Worksheets(2).Select
Cells.Find(What:="מודל תגובה", After:=ActiveCell, LookIn:=xlFormulas, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
ActiveCell.Offset(0, -1).Activate
If IsEmpty(ActiveCell.Value) = False Then
Selection.FindNext(After:=ActiveCell).Activate
ActiveCell.Offset(0, -1).Paste
Else
ActiveCell.Offset(0, -1).Select
ActiveCell.Paste
End If
i = i + 1
Loop
sorry for the shitty code(literally my first macro).
The solution would be to loop through the visible cells of the filtered range only.
Make sure the destination is filtered for "מודל תגובה" before running this code. It needs to look like your second image before running this code.
Dim SourceSheet As Worksheet
Set SourceSheet = Worksheets(1)
Dim DestinationSheet As Worksheet
Set DestinationSheet = Worksheets(2)
Dim LastRow As Long
LastRow = DestinationSheet.Cells(DestinationSheet.Rows.Count, "B").End(xlUp).Row
Dim VisibleCells As Range
On Error Resume Next 'next line errors if no visible cells so we turn error reporting off
Set VisibleCells = DestinationSheet.Range("A2", "A" & LastRow).SpecialCells(xlCellTypeVisible)
On Error Goto 0 'turn error reporting on or you won't see if other errors occur
If VisibleCells Is Nothing Then 'abort if no cells are visible in the filter
MsgBox "No cells to paste at"
Exit Sub
End If
Dim SourceRow As Long
SourceRow = 4 'start row in your source sheet
Dim Cell As Range
For Each Cell In VisibleCells.Cells 'loop through visible cells
Cell.Value = SourceSheet.Cells(SourceRow, "A").Value 'copy value
SourceRow = SourceRow + 1 'incerease source row
Next Cell
Make sure to define DestinationSheet and SourceSheet with your sheets names.
Try this:
Dim i As Integer
Dim Last_Row as Long
Worksheets(1).Select
'The "1" Of the line below means that the variable gonna count the rows of the first column (A)
Last_Row = Application.ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
Range("A1:A" & Last_Row).Copy
Worksheets(2).Select
Range("A1").Select
ActiveSheet.Paste

Is there a way to run Autofilter to more than one column simultaneously in Excel VBA?

I have a cell designated as a Search Box for user entry (called 'UserSearch') and need to be able to use this input to filter multiple columns at the same time. For example, if the user searched for 'Apple', I need the VBA code to filter out all rows where that word appears, even if it appeared in another column. I am currently stuck on only being able to filter out one column at a time but this input may also appear in another column but the row won't be filtered because it may have gotten filtered out by the column before it.
My current code is below is:
Sub search()
With ActiveSheet.Range("$a$4:$j$30")
.AutoFilter Field:=1, Criteria1:="=*" & Range("UserSearch") & "*", Operator:=xlOr
.AutoFilter Field:=2, Criteria1:="=*" & Range("UserSearch") & "*", Operator:=xlOr
.AutoFilter Field:=3, Criteria1:="=*" & Range("UserSearch") & "*"
End With
End Sub
As you can see, my goal is to be able to run autofilter on all 3 fields simultaneously (essentially treating the 3 columns as just one) but the code above contradicts each other and no rows are returned. Anyone have any idea by using autofilter?
You cannot use .AutoFilter for this but yes using a small vba code you can achieve what you want
Let's say your worksheet looks like this
Paste this code in a module
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim rngHide As Range
Dim FoundIt As Long, i As Long, lRow As Long
Dim SearchString As String
'~~> Your search string
SearchString = "Apple"
'~~> Change this to the relevant sheet
Set ws = Sheet1
'~~> Find the last row
' https://stackoverflow.com/questions/11169445/error-in-finding-last-used-cell-in-excel-with-vba
lRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
'~~> Loop through 4 to last row to find the search string
For i = 4 To lRow
On Error Resume Next
FoundIt = Application.WorksheetFunction.Match(SearchString, ws.Rows(i), 0)
On Error GoTo 0
'~~> Create a range which needs to be hidden
If FoundIt = 0 Then
If rngHide Is Nothing Then
Set rngHide = ws.Rows(i)
Else
Set rngHide = Union(rngHide, ws.Rows(i))
End If
End If
FoundIt = 0
Next i
'~~> Hide it if applicable
If Not rngHide Is Nothing Then rngHide.EntireRow.Hidden = True
End Sub
I have commented the code so you should not have a problem understanding it. but if you do then simply ask.
In Action
These two macros are more basic, but accomplish the same task as Sid's answer...
The first macro loops through the range and checks the first three cells in the current row for the search text, if found in any of the cells, it will loop to the next row. If no cells contain the search text, the row will be hidden
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1") 'Define your worksheet
Dim UserSearch As String: UserSearch = ws.Range("A2").Value 'Assign the range for the user entry, change as needed
For Each cel In ws.Range("A4", ws.Cells(ws.Rows.Count, 1).End(xlUp)) 'Loop through the range
'Using (= and Or) test if any of the first three cells in the current row contain the search text
If cel.Value = UserSearch Or cel.Offset(, 1).Value = UserSearch Or cel.Offset(, 2).Value = UserSearch Then
'If the search text is found in any of the cells then loop to the next row
Else
'If the search text is not in any of the cells then hide the row
cel.EntireRow.Hidden = True
End If
Next cel
The second macro loops through the range and checks the first three cells in the current row for the search text, if not found, the row will be hidden
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1") 'Define your worksheet
Dim UserSearch As String: UserSearch = ws.Range("A2").Value 'Assign the range for the user entry, change the range as needed
For Each cel In ws.Range("A4", ws.Cells(ws.Rows.Count, 1).End(xlUp)) 'Loop through the range
'Using (<> and And) test the first three cells in the current row
If cel.Value <> UserSearch And cel.Offset(, 1).Value <> UserSearch And cel.Offset(, 2).Value <> UserSearch Then
'If the search text is not found hide the current row
cel.EntireRow.Hidden = True
End If
Next cel

Find string in one worksheet and select it in another

I've got Workbook where I got names and hours worked of employees. I'm looking for comparing rows in one worksheet (Range B6:CC6) and find it in another with selection on cell with employee name (Range A1:A5000) when I change sheets from 1 to 2.
Tried some Range.Find and others, no idea how to do it
Public Sub FindPosition()
Dim Actcol As Integer, Pos As Range, Name As Range
Actcol = ActiveCell.Column
MsgBox "ActiveCell is" & Actcol
Set Pos = Cells(6, Actcol)
MsgBox Pos
Pos.Select
If Worksheets("Sheet2").Activate Then
Worksheets("Sheet2").Range("A1:AA5100").Select
Set Name = Selection.Find(Pos, LookIn:=xlValues)
End If
End Sub
First, if you want to trigger some macro by activation of Sheet2, you need to handle Activate event of Sheet2. This can be done by declaring subroutine in Sheet module like this.
Private Sub Worksheet_Activate()
'Codes you want to be run when Sheet2 is activated.
End Sub
Second, a simple way to find a cell with specific value is to use WorksheetFunction.Match. For example,
Dim SearchInRange As Range
Set SearchInRange = Range("A1:A5000")
Dim EmployeeName As Variant
EmployeeName = ... 'Actual employee name you want to search
On Error GoTo NotFound
Dim Index As Variant
Index = WorksheetFunction.Match(EmployeeName, SearchInRange, 0)
On Error GoTo 0
SearchInRange.Cells(Index).Select
GoTo Finally
NotFound:
' Handle error
Finally:
Range.Find may also work, but remember it has the side effect of changing the state of "Find and Replace" dialog box.
This may helps you
Option Explicit
Sub test()
Dim i As Long, LastRowA As Long, LastRowB As Long
Dim rngSearchValues As Range, rngSearchArea As Range
Dim ws1 As Worksheet, ws2 As Worksheet
'Set you worksheets
With ThisWorkbook
'Let say in this worksheet you have the names & hours
Set ws1 = .Worksheets("Sheet1")
'Let say in this worksheet you have the list of names
Set ws2 = .Worksheets("Sheet2")
End With
'Find the last row of the column B with the names from the sheet with names & hours
LastRowB = ws1.Cells(ws1.Rows.Count, "B").End(xlUp).Row
'Find the last row of the column A with the names from the sheet with list of names
LastRowA = ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row
'Set the range where you want to check if the name appears in
Set rngSearchArea = ws2.Range("A1:A" & LastRowA)
'Loop the all the names from the sheet with names and hours
For i = 6 To LastRowB
If ws1.Range("B" & i).Value <> "" Then
If Application.WorksheetFunction.CountIf(rngSearchArea, "=" & ws1.Range("B" & i).Value) > 0 Then
MsgBox "Value appears"
Exit For
End If
End If
Next i
End Sub
Oh right, I found solution. Thanks everyone for help.
Public Sub Position()
Dim Accol As Integer
Dim Pos As Range
Dim name As Range
ActiveSheet.name = "Sheet1"
Accol = ActiveCell.Column
Set Pos = Cells(6, Accol)
Worksheets("Sheet2").Activate
Worksheets("Sheet2").Range("a1:a5000").Select
Set name = Selection.Find(What:=Pos, After:=ActiveCell, LookIn:=xlValues, LookAt:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
name.Select
End Sub
Last thing I would like to do which I cannot solve is where do I write automatically script running when I choose Sheet2?

Copy column data consisting of blank cells

I am into a situation where I need to copy a range from a excel sheet and paste it to another. I have done the following coding which is going well...
Dim mpn As String
mpn = Application.InputBox(prompt:="Input the MPN column name:")
mpn1 = mpn
mpn2 = mpn1 & ":" & mpn
Set currentSheet = wbSource.Worksheets(1)
lastRow1 = currentSheet.Range(mpn1).End(xlDown).Row
ThisWorkbook.Sheets("Sheet2").Range("F2:F" & lastRow1) = currentSheet.Range(mpn2 & lastRow1).Value
This coding goes perfectly well untill there is any blank cell in the column. Can anyone please help me on this particular situation.
Like I mentioned in the comments above, instead of prompting for the column name, use .Find to locate the column name. What if user types Blah Blah in the input box?
Also as mentioned in comments use xlUp rather than xlDown to find the last row to counter for blank cells and other issues you may face. See this
Is this what you are trying? (Untested)
I have commented the code so you should not having a problem understanding it. But if you do then simply post back :)
Sub Sample()
Dim mpnCol As Long
Dim ColName As String, strSearch As String
Dim aCell As Range
Dim wbSource As Workbook
Dim wbInput As Worksheet, currentSheet As Worksheet
'~~> Change this to the Mpn Header
strSearch = "MPN"
'~~> This you have declared in your code
'~~> Change as applicable
Set wbSource = "Someworkbook"
Set currentSheet = wbSource.Worksheets(1)
Set wbInput = ThisWorkbook.Sheets("Sheet2")
With currentSheet
'~~> Search for the mpn header in row 1. Change as applicable
Set aCell = .Rows(1).Find(What:=strSearch, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
'~~> Column Number
mpnCol = aCell.Column
'~~> Converting column number to column name
ColName = Split(.Cells(, mpnCol).Address, "$")(1)
'~~> Getting last row
lRow = .Range(ColName & .Rows.Count).End(xlUp).Row
'~~> Checking for excel versions. Comment this if the copying
'~~> will always happen in xl2007+ versions
If lRow > 65536 Then
MsgBox "Are you trying to copy from xl2007 to xl2003?. The number of rows exceed the row limit"
Exit Sub
End If
wbInput.Range("F2:F" & lRow).Value = .Range(ColName & "2:" & ColName & lRow).Value
Else
MsgBox strSearch & " header not found"
End If
End With
End Sub
To copy an entire column, reference your range with the .Columns() function.
You could use something like:
ThisWorkbook.Sheets("Sheet2").Columns("F") =
currentSheet.Columns(mpn1).Value
Another alternative would be to use the .Copy sub and specify a Destination for the copy:
currentSheet.Columns(mpn1).Copy
Destination:=ThisWorkbook.Sheets("Sheet2").Columns("F")
Application.CutCopyMode = false
This answer assumes both workbooks are saved with the same version of Excel. If one workbook is pre-2007, and one is 2007+, then the max number of rows allowed in a sheet will be different.
In that case, copying the entire column is not an option - check out Siddarth's answer for a longer solution to that extra complication. He checks for different number of rows to prevent the error.

Trying to delete a row if no data in row A:J

I am trying to delete a row if there is no data from A:J
I have found this code and been trying to edit it, but this is deleting the whole sheet's data eventually.
Any help would be greatly appreciated
Sub DeleteRows()
Dim rngBlanks As Range
Dim i As Integer
For i = 1 To 10
On Error Resume Next
Set rngBlanks = Columns(i).SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not rngBlanks Is Nothing Then
rngBlanks.EntireRow.Delete
End If
Next
End Sub
Trying to delete a row if no data in row A:J
What code is doing is individually checking the columns and not the range A:J as your title suggests. It is very much possible that your entire data is getting deleted because of this. Lets say A1 has some data but B1 doesn't. So your code will delete Row 1. What you have to do is to check if say A1:J1 is blank.
I think this is what you are trying?
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim rngBlanks As Range
Dim i As Long, lRow As Long, Ret As Long
'~~> Set this to the relevant worksheet
Set ws = ThisWorkbook.Sheets("Sheet2")
With ws
'~~> Get the last row in that sheet
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lRow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Else
lRow = 1
End If
'~~> Loop through the rows to find which range is blank
For i = 1 To lRow
Ret = Application.Evaluate("=COUNTA(A" & i & ":J" & i & ")")
If Ret = 0 Then
If rngBlanks Is Nothing Then
Set rngBlanks = .Rows(i)
Else
Set rngBlanks = Union(rngBlanks, .Rows(i))
End If
End If
Next i
End With
'~~~> Delete the range
If Not rngBlanks Is Nothing Then rngBlanks.Delete
End Sub
Another way would be to use Autofilter to delete those ranges
I stepped through your code with a sheet having some non-blank cells in columns A:J down to row 15. Rows 16:18 were entirely blank and D19=1. You want to delete rows that have blanks in every cell from A:J.
On the first iteration of your For..Next loop rngBlanks was not Nothing because typing
?rngBlanks.address
returned $A$1,$A$5:$A$19. A2:A4 were not blank. When you execute
Set rngBlanks = Columns(i).SpecialCells(xlCellTypeBlanks)
it looks for any blanks in column A which is not what you wanted to test. You want to test each row, probably within your ActiveSheet.UsedRange to see if columns A:J are all blank. So you need to define a variable
Dim Rw as Range
and iterate through each Rw in UsedRange
For Each Rw in ActiveSheet.UsedRange
If WorksheetFunction.CountBlank(range(cells(Rw,1),cells(Rw,10))) =0 Then
Rw.EntireRow.Delete
I could post the entire code here but what I've given should put you on the right track.

Resources