would anyone be able to help?
I am trying to write VBA to highlight if the cell has 2 different values. It seems to highlight all including the same name appear twice. Thanks for any help!
Sub CountTwoOrMoreDifferent()
Dim myRange As Long
myRange = Cells(Rows.Count, "A").End(xlUp).Row
Range("A2:A" & myRange).Select
For Each AnimalName In Selection
AnimalNameMoreThan2 = AnimalName.Value
If InStr(AnimalNameMoreThan2, "Cat") + _
InStr(AnimalNameMoreThan2, "Dog") + _
InStr(AnimalNameMoreThan2, "Cow") _
+ InStr(AnimalNameMoreThan2, "Chicken") + _
InStr(AnimalNameMoreThan2, "Snake") + _
InStr(AnimalNameMoreThan2, "Tums") + _
InStr(AnimalNameMoreThan2, "Drop") > 1 Then
AnimalName.Interior.Color = vbRed
End If
Next AnimalName
End Sub
Data in column A
Sample Data
You can use this code.
It is split into two parts
a sub - which does the check per cell.
a function that checks if there is a duplicate within an array.
It returns true in case there is at least one dup.
Public Sub highlightDuplicateValues()
'get Range to check
Dim lastRow As Long, rgToCheck As Range
With ActiveSheet
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rgToCheck = .Range("A2:A" & lastRow) 'no need to select!
End With
Dim c As Range, arrValuesInCell As Variant
Dim i As Long
For Each c In rgToCheck.Cells
'get an array of values/animals in cell
arrValuesInCell = Split(c.Value, ";")
'now check for each value if it has a dup - if yes color red and exit check
For i = LBound(arrValuesInCell) To UBound(arrValuesInCell)
If hasDupInArray(arrValuesInCell, i) = True Then
c.Interior.Color = vbRed
Exit For
End If
Next
Next
End Sub
Private Function hasDupInArray(arrValues As Variant, checkI As Long) As Boolean
'only values after the checkI-value are checked.
'Assumption: previous values have been checked beforehand
Dim varValueToCheck As Variant
varValueToCheck = arrValues(checkI)
Dim i As Long
For i = checkI + 1 To UBound(arrValues)
If arrValues(i) = varValueToCheck Then
hasDupInArray = True
Exit For
End If
Next
End Function
I am attempting to compare two columns in two separate sheets, each column contains data that is a string. My issue is that there is data in one column that is identical to the other in separate rows; therefore I have to check the entire column for the data before moving to the next. I am very inexperienced with VBA and am trying to make one portion of my job easier rather than comparing the columns by hand. I have piece wised the following code from research and trial and error. I am able to get the entire Column searched in my first Sheet, but only one value is being highlighted on the second sheet and then it is returning a value of "True" in the first column. I am unsure where I have gone wrong, any help is greatly appreciated!
Sub Better_Work_This_Time()
Dim FindString As String
Dim Rng As Range
ActiveCell = Sheets("Last Week").Range("A2").Activate
FindString = ActiveCell
Dim County As Integer
Count = Cells.CurrentRegion.rows.Count
For i = 2 To County
If Trim(FindString) <> "" Then
With Sheets("Current Week").Range("A:A")
Set Rng = .Find(What:=FindString, After:=.Cells(.Cells.Count), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=True)
If Not Rng Is Nothing Then
ActiveCell.Font.Color = vbBlue
End If
End With
End If
If IsEmpty(FindString) Then
FindString = False
End If
ActiveCell.Offset(1, 0).Select
i = i + 1
Next
End Sub
Without using ActiveCell and using Match instead of Find.
Option Explicit
Sub Does_Work_This_Time()
Dim wb As Workbook, wsLast As Worksheet, wsCurrent As Worksheet
Dim FindString As String, ar, v
Dim LastRow As Long, i As Long, n As Long
Set wb = ThisWorkbook
' put current week values into array
Set wsCurrent = wb.Sheets("Current Week")
With wsCurrent
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
ar = .Range("A2:A" & LastRow).Value2
End With
' scan last week matching current week
Set wsLast = wb.Sheets("Last Week")
With wsLast
.Columns(1).Interior.Color = xlNone
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 2 To LastRow
FindString = Trim(.Cells(i, "A"))
If Len(FindString) > 0 Then
v = Application.Match(FindString, ar, 0)
If IsError(v) Then
'no match
ElseIf ar(v, 1) = FindString Then ' case match
.Cells(i, "A").Interior.Color = RGB(128, 255, 128) ' light green
n = n + 1
End If
End If
Next
End With
MsgBox n & " rows matched"
End Sub
I'm currently reorganizing some columns using VBA code and I need to make a change to one of the header rows and the values in 1 specific column. I've included what I'm basically trying to do in a comment. Here is the code I'm using but very cut down for brevity.
Sub columnOrder2()
Dim search As Range
Dim cnt As Integer
Dim colOrdr As Variant
Dim indx As Integer
colOrdr = Array("User name", "LanID", "Asset Tag")
cnt = 1
For indx = LBound(colOrdr) To UBound(colOrdr)
Set search = Rows("1:1").Find(colOrdr(indx), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False)
' If search = "LanID" then change header row to "Last3"
' and return only the last 3 characters for values in cells
If Not search Is Nothing Then
If search.Column <> cnt Then
search.EntireColumn.Cut
Columns(cnt).Insert Shift:=xlToRight
Application.CutCopyMode = False
End If
cnt = cnt + 1
End If
Next indx
End Sub
Currently, I'm just running the code and manually renaming the column then creating a formula in cell g2 and using =Right(G2,3) and copying it down to the rest of the cells in column C. I know VBA can do this much better and maybe even just in a separate function. Any help would be appreciated. I haven't worked with Excel VBA for awhile now.
Assuming you mean to overwrite the LANId column with its own last three characters, you could code as follows (C2 instead of G2 in your question?):
Modified code close to OP
Includes a fully qualified (worksheet) range reference, btw (as otherwise VBA assumes any currently active worksheet) :-)
Sub columnOrder2()
Dim ws As Worksheet: Set ws = Sheet1 ' << Using e.g. the sheet's Code(Name)
Dim colOrdr As Variant
colOrdr = Array("User name", "LanID", "Asset Tag")
Dim cnt As Long
cnt = 1
Dim indx As Long
For indx = LBound(colOrdr) To UBound(colOrdr)
Dim search As Range
Set search = ws.Rows("1:1").Find(colOrdr(indx), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False)
If Not search Is Nothing Then
If LCase(search.Text) = "lanid" Then
'set column range object to memory
Dim rng As Range
Set rng = getColRange(ws, search.Column, Startrow:=1)
'return only the last 3 characters
rng.Value = Evaluate("=Right(" & rng.Address & ",3)")
'change header cell from "LANId" to "Last3"
rng(1, 1) = "Last3" ' change header from LANId to Last3
End If
If search.Column <> cnt Then
search.EntireColumn.Cut
Columns(cnt).Insert Shift:=xlToRight
Application.CutCopyMode = False
End If
cnt = cnt + 1
End If
Next indx
End Sub
Help function
Returns the range of a given sheet column up to the last row with a value:
Function getColRange(mySheet As Worksheet, _
Optional ByVal myColumn As Variant = "A", _
Optional ByVal Startrow As Long = 1) As Range
With mySheet
'a) change numeric column number to letter(s)
If IsNumeric(myColumn) Then myColumn = Split((.Columns(myColumn).Address(, 0)), ":")(0)
'b) get last row in given column
Dim lastRow As Long
lastRow = .Range(myColumn & .Rows.Count).End(xlUp).Row
'c) return data range as function result
' (a Range is an Object and has to be SET!)
Set getColRange = .Range(myColumn & Startrow & ":" & myColumn & lastRow)
End With
End Function
Related link
Instead of moving entire columns one after the other you might be interested in an array approach - c.f. Delete an array column and change position of two columns
I am facing problem with removing duplicate from a single row. I want to loop through all rows in a range and remove duplicate from a single row without effecting rest of data in sheet. Here is sample data:
+---------------+------+------+------+---------------+---------------+
| name | num1 | num2 | mun3 | emial1 | email2 |
+---------------+------+------+------+---------------+---------------+
| ali zubair | 1 | 2 | 1 | az#az.com | az#az.com |
+---------------+------+------+------+---------------+---------------+
| tosif | 1 | 2 | 2 | t#zb.com | t#gb.com |
+---------------+------+------+------+---------------+---------------+
| qadeer satter | 3 | 2 | 3 | qs#mtm.com | star#mtn.com |
+---------------+------+------+------+---------------+---------------+
| asif | 4 | 3 | 2 | | |
+---------------+------+------+------+---------------+---------------+
| hamid | 1 | 5 | 2 | hamid#beta.ds | hamid#beta.ds |
+---------------+------+------+------+---------------+---------------+
Below code removes duplicate rows based on column 2, it is not applicable in my case.
ActiveSheet.Range("A1:f100").RemoveDuplicates Columns:=Array(2), Header:=xlYes
I have no idea how I can remove duplicate from a selected row range. So far I have the code that will loop through all rows in my data.
Sub removeRowDubs()
Dim nextRang As Range
Dim sCellStr As String, eCellStr As String
Dim dRow As Long
dRow = Cells(Rows.Count, 1).End(xlUp).Row
For dRow = 2 To dRow
sCellStr = Range("A" & dRow).Offset(0, 1).Address
eCellStr = Cells(dRow, Columns.Count).End(xlToLeft).Address
Set nextRang = Range(sCellStr, eCellStr)
Debug.Print nextRang.Address
Next
End Sub
So what I need is some code to do what I need inserted after below code.
Set nextRang = Range(sCellStr, eCellStr)
If there is a simple solution to this like ".RemoveDuplicates" then please let me know. As of now I am thinking of doing this through looping but it seems complex as I think I will need at least 3 "for each" loops and 3 "if conditions", 2 more row ranges and probably something else when I start doing it like that.
I hope I made my question clear and I will really appreciate your help. I am new at Excel VBA coding, your patience is needed..
So I also worked on the code to remove duplicates for rows. Below is my code, its working for me. It is complex and people over stackoverflow provided better code.
Sub removeRowDublicates()
Dim nextRang As Range ' Variables for
Dim sCellStr As String, eCellStr As String ' Going through all rows
Dim dRow As Long ' And selecting row range
dRow = Cells(Rows.Count, 1).End(xlUp).Row ' This code selects the
For dRow = 2 To dRow ' next row in the data
sCellStr = Range("A" & dRow).Offset(0, 1).Address
eCellStr = Cells(dRow, Columns.Count).End(xlToLeft).Address
Set nextRang = Range(sCellStr, eCellStr)
Dim aRange As Range, aCell As Range ' Variables for
Dim dubCheckCell As Range, dubCheckRange As Range ' Loops to remove
Dim dubCheckCell1 As Range ' Dublicates from
Dim columnNum As Integer ' Current row
Set aRange = nextRang
columnNum = Range("b2:f2").Columns.Count + 1
aRange.Select
For Each aCell In aRange 'Loop for selecting 1 cell, if not blank from range to check its value against all other cell values
If aCell.Value <> "" Then
Set dubCheckCell = aCell
Else
GoTo nextaCell 'If current cell is blank then go to next cell in range
End If
If dubCheckCell.Offset(0, 2).Value <> "" Then 'Selects range by offsetting 1 cell to right from current cell being checked for dublicate value
Set dubCheckRange = Range(dubCheckCell.Offset(, 1), dubCheckCell.Offset(, 1).End(xlToRight))
Else
Set dubCheckRange = Range(dubCheckCell.Offset(0, 1).Address)
End If
For Each dubCheckCell1 In dubCheckRange 'Loop that goes through all cells in range selected by above if-statement
Do While dubCheckCell1.Column <= columnNum
If dubCheckCell = dubCheckCell1 Then
dubCheckCell1.ClearContents
Else
End If
GoTo nextdubCheckCell1
Loop 'For do while
nextdubCheckCell1:
Next dubCheckCell1 'Next for dubCheckRange
nextaCell:
Next aCell 'Next for aRange
Next 'For drow
End Sub
Try the next code, please:
Sub testRemoveRowDuplicates()
Dim sh As Worksheet, rng As Range, lastRow As Long, i As Long
Set sh = ActiveSheet 'use here your sheet
lastRow = sh.Range("A" & Rows.Count).End(xlUp).row
For i = 2 To lastRow
Set rng = sh.Range("C" & i & ":D" & i)
rng.Replace rng.Cells(1, 1).Offset(0, -1).Value, "", xlWhole
Set rng = sh.Range("D" & i)
rng.Replace rng.Cells(1, 1).Offset(0, -1).Value, "", xlWhole
Set rng = sh.Range("F" & i)
rng.Replace rng.Cells(1, 1).Offset(0, -1).Value, "", xlWhole
Next i
End Sub
The above code assumes that a name cannot be duplicate in the email columns. It removes duplicates on each category (names and emails).
If you really need to check each value of the row, please, use the next variant:
Sub testRemoveRowDuplicatesBis()
Dim sh As Worksheet, rng As Range, lastRow As Long
Dim i As Long, j As Long
Set sh = ActiveSheet
lastRow = sh.Range("A" & Rows.Count).End(xlUp).row
For i = 2 To lastRow
For j = 3 To 6 'last column
Set rng = sh.Range(sh.Cells(i, j), sh.Cells(i, 6))
rng.Replace rng.Cells(1, 1).Offset(0, -1).Value, "", xlWhole
Next j
Next i
End Sub
You can use some VBA nested loops to do this - loop the rows, and then have two column loops to check the values of the cells:
Sub sRemoveRowDubs()
On Error GoTo E_Handle
Dim ws As Worksheet
Dim lngLastRow As Long
Dim lngLastCol As Long
Dim lngRow1 As Long
Dim lngCol1 As Long
Dim lngCol2 As Long
Set ws = Worksheets("Sheet4")
lngLastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
lngLastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
For lngRow1 = 1 To lngLastRow
For lngCol1 = 1 To lngLastCol
For lngCol2 = lngCol1 + 1 To lngLastCol
If ws.Cells(lngRow1, lngCol1) = ws.Cells(lngRow1, lngCol2) Then
ws.Cells(lngRow1, lngCol2) = ""
End If
Next lngCol2
Next lngCol1
Next lngRow1
sExit:
On Error Resume Next
Set ws = Nothing
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "sRemoveRowDubs", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume sExit
End Sub
Regards,
If you can use formula and create a new table.
Array (CSE) Formula for Num1 column, enter the formula in formula bar, press control+Shift+Enter and then select the cell copy to Num2 and Num3. Then select all three cells and copy down.
=IFERROR(INDEX($B2:$D2,1,MATCH(0,COUNTIF($H2:H2,$B2:$D2),0)),"")
Array (CSE) Formula for email1 column, enter the formula in formula bar, press control+Shift+Enter and then select the cell copy to email2. Then select those two cells and copy down.
=IFERROR(INDEX($E2:$F2,1,MATCH(0,COUNTIF($K2:K2,$E2:$F2),0)),"")
Or maybe something like this?
Sub test()
Set rngName = Range("A2", Range("A" & Rows.Count).End(xlUp))
For Each cell In rngName
For i = 1 To 4
Set Rng = Range(cell.Offset(0, i + 1), Cells(cell.Row, 6))
Set c = Rng.Find(cell.Offset(0, i).Value, lookat:=xlWhole)
If Not c Is Nothing Then c.ClearContents
Next i
Next cell
End Sub
What I am thinking is selecting 1 cell from row then check it against
all other cells in the same row
The code assumes that there will be no blank in between row with value under column NAME (column A), and all the name value is unique. This is for the first loop.
The second loop is the how many cell in the same row to check, in this case there are 4 cells to check (num1, num2, num3 and email1) then so does the checking are 4 times ---> in the same row : check num1 against num2, num3, email1 and email2 ... check num2 against num3, email1 and email2 .... check num3 against email1 and email2... then finally check email1 against email2. On each check, if the same value is found, then the code put blank to the found cell.
Clear Duplicate Entries By Row
Copy the complete code into a standard module (e.g. Module1).
Only run the first Sub, the other two are being called.
Adjust the constants in the first Sub, including the workbook.
The Code
Option Explicit
Sub clearDups()
Const wsName As String = "Sheet1"
Const FirstRowAddress As String = "A2:F2"
Const LastRowColumn As Long = 1
Const Replacement As Variant = Empty
Dim wb As Workbook: Set wb = ThisWorkbook
' Define Data First Row Range.
Dim rng As Range: Set rng = wb.Worksheets(wsName).Range(FirstRowAddress)
' Define Data Range and write its values to Data Array.
Dim Data As Variant: getRangeValuesFR Data, rng, LastRowColumn
If IsEmpty(Data) Then Exit Sub
' In data array, clear duplicate values by row
' (from the top and from the left).
replaceDupsByRow Data, Replacement
' Write modified values from Data Array to Data Range.
rng.Resize(UBound(Data)).Value = Data
End Sub
Sub getRangeValuesFR(ByRef Data As Variant, _
ByRef FirstRowRange As Range, _
Optional ByVal LastRowColumn As Long = 1)
Dim rng As Range
If LastRowColumn = 0 Then GoSub LastRow0 Else GoSub LastRowN
If rng Is Nothing Then Exit Sub
If rng.Row < FirstRowRange.Row Then Exit Sub
Set rng = FirstRowRange.Resize(rng.Row - FirstRowRange.Row + 1)
If rng.Row > 1 Then
Data = rng.Value
Else
ReDim Data(1 To 1, 1 To 1): Data(1, 1) = rng.Value
End If
Exit Sub
LastRow0:
With FirstRowRange
Set rng = .Worksheet.Columns(.Column).Resize(, .Columns.Count) _
.Find("*", , xlValues, , xlByRows, xlPrevious)
End With
Return
LastRowN:
With FirstRowRange
Debug.Print .Columns(LastRowColumn).Address
Set rng = .Worksheet.Columns(.Columns(LastRowColumn).Column) _
.Find("*", , xlValues, , , xlPrevious)
End With
Return
End Sub
Sub replaceDupsByRow(ByRef Data As Variant, _
Optional ByVal Replacement As Variant = Empty)
Dim Curr As Variant, i As Long, j As Long, l As Long
For i = 1 To UBound(Data)
For j = 1 To UBound(Data, 2) - 1
Curr = Data(i, j + 1)
If Curr <> Replacement Then GoSub loopSubRows
Next j
Next i
Exit Sub
loopSubRows:
For l = 1 To j
If Curr = Data(i, l) Then
Data(i, j + 1) = Replacement: Exit For
End If
Next l
Return
End Sub
I have a spreadsheet that calls out jobs with agents assigned. The "agent ID" is in column A, with data in columns A-M.
I have separate sheets for each of the agent's supervisor (supervisor last name). I was hard coding the agent ID into the macro but I would like to make it work so I could pull that data from a translation sheet which would hold nothing more than the agent ID and corresponding supervisor last name. I can't figure out how to parse through the data row by row, find the agent id, then copy that row to the corresponding sheet.
I already have the translation sheet (named sup-agent_Trans) with AgentID, Supervisor; that's it, those two columns.
Here is what I have so far:
Dim varList As Variant
Dim lstRowTrans As Long
Dim lstRowRework As Long
Dim rngArr As Range
Dim rngRwk As Range
Dim row As Range
Dim cell As Range
Application.ScreenUpdating = False
lstRowTrans = Worksheets("Tech-Sup_Trans").Cells(Rows.Count, "A").End(xlUp).row
lstRowRework = Worksheets("Rework").Cells(Rows.Count, "A").End(xlUp).row
varList = Sheets("Tech-Sup_Trans").Range("A1:B" & lstRowTrans)
Set rngRwk = Sheets("Rework").Range("A1:A" & lstRowRework)
For Each cell In rngRwk
For i = LBound(varList, 2) To UBound(varList, 2) 'columns
If i = cell(i).Value <> "" Then
For j = LBound(varList, 1) To UBound(varList, 1) 'rows
If varList(j, cell(i).Value) Then
IsInArray = True
End If
Next j
End If
Next i
Next cell
So after someone so graciously pointed out that I don't need to use an array, I used the "Find" function for a range and figured it out. Thanks findwindow!
Dim shtRwk As Worksheet
Dim shtRef As Worksheet
Dim DestCell As Range
Dim rngRwk As Range
Dim lstRowTrans As Long
Dim lstRowRework As Long
Dim rngArr As Range
Dim row As Range
Dim cell As Range
Dim strSup As String
Set shtRwk = Sheets("Rework")
Set shtRef = Sheets("Tech-Sup_Trans")
Application.ScreenUpdating = False
lstRowTrans = shtRef.Cells(Rows.Count, "A").End(xlUp).row
lstRowRework = shtRwk.Cells(Rows.Count, "A").End(xlUp).row
Set rngRwk = Sheets("Rework").Range("A2:A" & lstRowRework)
For Each cell In rngRwk
With shtRef.Range("A1:B" & lstRowTrans)
Set DestCell = .Find(What:=cell.Value, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not DestCell Is Nothing Then
strSup = DestCell.Offset(0, 1).Value
cell.EntireRow.Copy
Sheets(strSup).Select
ActiveSheet.Range("A65536").End(xlUp).Select
Selection.Offset(1, 0).Select
ActiveSheet.Paste
shtRwk.Select
Else
MsgBox "No Sup found for tech " & cell.Value
End If
End With
Next cell
Application.ScreenUpdating = True