I am new for doing Excel VBA coding. And I would like to write a simple coding which is highlight the duplicate number
If my ShpMarkLog(test) worksheet SMOrder_No = TALLY-SHEET Order No.
Then
If my ShpMarkLog(test) worksheet SMNewCTNno = TALLY-SHEET (Column H8 TO AK103)
Then Hightlight the duplicate number.
Then
If the TALLY-SHEET (Column H8 TO AK103) is blank, then put white colour with blank.
But when the system didn't follow my criteria, which is only highlight the number if the SMOrder_No = Order No.
Below is my coding.
Option Explicit
Sub Compare()
Dim sh, wsh As Worksheet
Set sh = Sheets("ShpMarkLog(test)")
Set wsh = Sheets("TALLY-SHEET")
Dim x As Long
x = sh.Range("A" & Rows.Count).End(xlUp).Row
Dim myRange, myRange2 As Range
Set myRange = sh.Range("I9", "I" & x)
Set myRange2 = sh.Range("J9", "J" & x)
Dim p, i As Long
p = wsh.Range("A" & Rows.Count).End(xlUp).Row
Dim b, b2 As Integer
b = 1
For i = 8 To 103
For b2 = 8 To 37
If wsh.Cells(i, b2) = "" Then
wsh.Cells(i, b2).Interior.ColorIndex = 2
Else
If Application.WorksheetFunction.CountIf(myRange2, wsh.Cells(i, b2)) > 0 And Application.WorksheetFunction.CountIf(myRange, wsh.Cells(i, b)) > 0 Then
wsh.Cells(i, b2).Interior.ColorIndex = 6
Else
wsh.Cells(i, b2).Interior.ColorIndex = 2
End If
End If
Next b2
Next i
End Sub
enter image description here
enter image description here
I Want to make the number only highlight duplicate when the criteria is meet. May I know how should I modify the code in order to get my result.
Really really thank you.
Sub HighlightDuplicates()
Dim rng1 As Range, rng2 As Range, rng3 As Range, cell As Range
Set rng1 = Worksheets("ShpMarkLog (test)").Range("SMOrder_No")
Set rng2 = Worksheets("TALLY-SHEET").Range("A2:A103")
Set rng3 = Worksheets("TALLY-SHEET").Range("H8:AK103")
For Each cell In rng1
If cell = rng2(cell.Row) Then
For Each c In rng3
If c = cell And c.Value <> "" Then
c.Interior.Color = RGB(255, 0, 0)
End If
Next c
End If
Next cell
For Each c In rng3
If c.Value = "" Then
c.Interior.Color = RGB(255, 255, 255)
End If
Next c
End Sub
Related
I'm trying to create a loop on the below code so if there are multiple matches of Column A to Column B it continue to fill out column B with the data from column A.
I've been suggested to create variant arrays and loop arrays, but I'm not that advanced yet after looking into it. Thanks.
Sub Test_match_fill_data()
Dim aCell
Dim e, k As Long, matchrow As Long
Dim w1, w2 As Worksheet
Dim cell As Range
Set w1 = Workbooks("Book1").Sheets("Sheet1")
Set w2 = Workbooks("Book2").Sheets("Sheet2")
e = w1.Cells(w1.Rows.Count, 1).End(xlUp).Row
k = w2.Cells(w2.Rows.Count, 1).End(xlUp).Row
For Each aCell In w1.Range("A2:A" & e)
On Error Resume Next
matchrow = w2.Columns("A:A").Find(What:=Left$(aCell.Value, 6) & "*", LookAt:=xlWhole).Row
On Error GoTo 0
If matchrow = 0 Then
Else
w2.Range("B" & matchrow).Value = aCell.Offset(0, 1).Value
End If
matchrow = 0
Next
End Sub
Your code would work if you searched Book1 for values from Book2. Here is an array version.
Option Explicit
Sub Test_match_fill_data()
Dim w1 As Worksheet, w2 As Worksheet
Dim ar1, ar2, matchrow, n As Long
Dim lastRow As Long, i As Long, s As String
Set w1 = Workbooks("Book1").Sheets("Sheet1")
With w1
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
ar1 = .Range("A2:B" & lastRow).Value2
End With
Set w2 = Workbooks("Book2").Sheets("Sheet2")
With w2
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
ar2 = .Range("A2:B" & lastRow).Value2
End With
For i = 1 To UBound(ar2)
s = Left(ar2(i, 1), 6)
If Len(s) > 0 Then
matchrow = Application.Match(s & "*", Application.Index(ar1, 0, 1), 0)
'Debug.Print i, s, matchrow
If Not IsError(matchrow) Then
ar2(i, 2) = ar1(matchrow, 2)
n = n + 1
End If
End If
Next
' copy array back to sheet
w2.Range("A2:B" & UBound(ar2) + 1) = ar2
MsgBox n & " rows updated"
End Sub
You can use the INDEX/MATCH formula - and then replace the results by values - no need for an array etc.
I put my assumptions in the code
Sub insertConsultants()
Dim wb1 As Workbook
Set wb1 = Workbooks("wb1.xlsx")
Dim rgDataSource As Range
'Assumption: Make = column A - first value in A3
'maybe you have to adjust this to your needs
'CurrentRegion: no empty rows within in data area
Set rgDataSource = wb1.Worksheets(1).Range("A3").CurrentRegion
Dim wb2 As Workbook: Set wb2 = Workbooks("wb2.xlsx")
Dim rgTarget As Range
'Assumption: Make = column A - first value in A3
'maybe you have to adjust this to your needs
Set rgTarget = wb2.Sheets(1).Range("A3").CurrentRegion
With rgTarget .Offset(, 1).Resize(, 1)
' = consultants column
.Formula = "=INDEX(" & rgDataSource.Columns(2).Address(True, True, , True) & ",MATCH(A3," & rgDataSource.Columns(1).Address(True, True, , True) & ",0))"
.Value = .Value
End With
End Sub
IMPORTANT: you always have to define each variable indivdually:
With your code Dim w1, w2 As Worksheet w1 is a variant not a worksheet. This could lead to errors.
I am trying to replicate what a Data Table does in excel in VBA. I have got the code working as I want thus far however when I copy data out of the temporary storage array it is offset by 1 Column and 1 Row.
I cannot figure out what the issue is? Thanks in advance.
Sub DataTableLoop()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Dim CodeRng As Range
Dim PasteRng As Range
Dim WatchRng As Range
Dim ResultRng As Range
Dim ResultRes As Range
Dim x As Integer
Dim y As Integer
Dim i As Integer
Dim Count As Integer
Dim col As Integer
Dim MyArray As Variant
Dim TempArr As Variant
Dim CodeVar As Range
Set CodeRng = Worksheets("OptionCodes").[CodeTop]
Set PasteRng = Worksheets("OptionCodes").[OptionsCode]
Set WatchRng = Worksheets("OptionCodes").[WatchRange]
Set ResultRng = Worksheets("OptionCodes").[ResultsRange]
col = WatchRng.Columns.Count
x = Worksheets("OptionCodes").[Iterations].Value
y = x - 1
i = 0
Set ResultRes = ResultRng.Resize(x)
ReDim MyArray(x, col)
Do While i <= y
Set CodeVar = CodeRng.Offset(i, 0)
Count = i + 1
Application.StatusBar = "Iteration: " & Count & " of " & x
CodeVar.Copy
PasteRng.PasteSpecial Paste:=xlPasteValues
Application.Calculate
TempArr = WatchRng
For j = 1 To col
MyArray(Count, j) = TempArr(1, j)
Next j
i = i + 1
Loop
ResultRes = MyArray
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Redim is by default 0 based, so your array is actually 1 row and column larger than you expect. To get 1 based you need to specify the lower bounds
ReDim MyArray(1 To x, 1 To col)
I cannot get to work condition for matching 2D arrays. I have tried another approach and this one is closer to the solution, but still does not produce the outcome.
This is what I want to do:
In sheet1 I have different dates that go through columns and size is uncertain. Below these dates are the values:
In sheet 2, I have a smaller subset of dates (that should exist in sheet1):
Through the code, I want to match the dates in sheet1 and sheet2, and only if match is true, I want to write the corresponding values from sheet1 to sheet2.
This is the outcome:
I want to use Arrays for dates in sheet1 and sheet2 and if they match, write the array of values. But the arrays of dates turn to be empty and so condtion for match does not work. I am not getting any error message as well:
Sub test()
Dim arrAmounts() As Variant
Dim arrDates_w2() As Variant
Dim arrDates_w1() As Variant
Dim Lastcol_w2 As Integer
Dim Lastcol_w1 As Integer
Dim LastRow As Integer
Dim i As Integer
Dim w As Integer
Dim d As Integer
Dim f As Integer
Dim g As Integer
Dim w1 As Worksheet
Dim w2 As Worksheet
Set w1 = Sheets("Sheet1")
Set w2 = Sheets("Sheet2")
LastRow = 17 'last row on both sheets
f = 1
g = 1
With w2
Lastcol_w2 = .Cells(3, Columns.Count).End(xlToLeft).Column
'array of dates in w2
ReDim arrDates_w2(1, Lastcol_w2)
End With
With w1
Lastcol_w1 = .Cells(3, Columns.Count).End(xlToLeft).Column
'Assign arrays:
ReDim arrAmounts(LastRow, Lastcol_w1)
ReDim arrDates_w1(1, Lastcol_w1)
For i = 1 To LastRow
For d = 1 To UBound(arrDates_w1, 2)
arrAmounts(i, d) = .Cells(3 + i, 2 + d)
Next
Next
'Match the dates in worksheets 1 and 2
For i = 1 To LastRow
For w = 1 To UBound(arrDates_w2, 2)
For d = 1 To UBound(arrDates_w1, 2)
If arrDates_w2(1, w) = arrDates_w1(1, d) Then
w2.Cells(i + 3, 2 + w) = arrAmounts(i, f + 3)
End If
Next
Next
Next
End With
End Sub
I would appreciate suggestions.
Please try this code.
Option Explicit
Sub CopyColumns()
Const CaptionRow As Long = 3 ' on all sheets
Const FirstClm As Long = 3 ' on all sheets
Dim WsIn As Worksheet ' Input sheet
Dim WsOut As Worksheet ' Output sheet
Dim DateRange As Range ' dates on WsIn
Dim Cin As Long ' input column
Dim Rl As Long ' last row in WsIn
Dim Cl As Long ' last used column in WsOut
Dim C As Long ' column counter in WsOut
Dim Arr As Variant ' transfer values
Set WsIn = Worksheets("Sheet1")
Set WsOut = Worksheets("Sheet2")
With WsIn
Set DateRange = .Range(.Cells(CaptionRow, FirstClm), .Cells(CaptionRow, .Columns.Count).End(xlToLeft))
End With
With WsOut
Cl = .Cells(CaptionRow, .Columns.Count).End(xlToLeft).Column
For C = FirstClm To Cl
On Error Resume Next
Cin = Application.Match(.Cells(CaptionRow, C).Value2, DateRange, 0)
If Err = 0 Then
Cin = Cin + DateRange.Column - 1
Rl = WsIn.Cells(WsIn.Rows.Count, Cin).End(xlUp).Row
Arr = WsIn.Range(WsIn.Cells(CaptionRow + 1, Cin), WsIn.Cells(Rl, Cin)).Value
.Cells(CaptionRow + 1, C).Resize(UBound(Arr)).Value = Arr
End If
Next C
End With
End Sub
What do you expect ReDim arrDates_w2(1, Lastcol_w2) to be doing? As it stands, it's only re-sizing the number of items that can be held in the array... You need to assign the Range to it: arrDates_w2 = w2.Range("C3:K3").Value for example. This will create a multi-dimensional array.
Then you can loop the items. Here's some sample code to illustrate the principle
Sub GetArrayInfo()
Dim a As Variant, i As Long, j As Long
Dim w2 As Worksheet
Set w2 = Sheets("Sheet2")
a = ws.Range("C3:K3").Value2
Debug.Print UBound(a, 1), UBound(a, 2)
For j = 1 To UBound(a, 2)
For i = 1 To UBound(a, 1)
Debug.Print a(i, j)
Next
Next
End Sub
Try
Sub test()
Dim Ws As Worksheet, Ws2 As Worksheet
Dim c As Integer, j As Integer, p As Integer
Dim i As Long, r As Long
Dim arr1() As Variant, arr2() As Variant
Dim rngDB As Range, rngHead As Range
Set Ws = Sheets("Sheet1")
Set Ws2 = Sheets("Sheet2")
With Ws
c = .Cells(3, Columns.Count).End(xlToLeft).Column
r = .Range("c" & Rows.Count).End(xlUp).Row
Set rngHead = .Range("c3", .Cells(3, c))
arr1 = .Range("c3", .Cells(r, c))
End With
With Ws2
c = .Cells(3, Columns.Count).End(xlToLeft).Column
Set rngDB = .Range("c3", .Cells(r, c))
arr2 = rngDB
End With
For j = 1 To UBound(arr2, 2)
p = WorksheetFunction.Match(arr2(1, j), rngHead, 0)
For i = 2 To UBound(arr2, 1)
arr2(i, j) = arr1(i, p)
Next i
Next j
rngDB = arr2
End Sub
I would like to go through a range of values in Column D and take each value:
for each value
check in the same range for its occurrence
check in the row of its occurrence for a value in column A
Add this value in column a to an array (or another way to save data)
go to the next occurrence of the value in column D and save the next Value of Column A to the array
When I checked each value for all its occurrences and added it to the array I want the array to be given out in the cell H1 (and for the next values onwards, I1 and so on)
Here's a picture of what I mean with some dummy values:
My attempts in VBA so far are this (with the remark that I deal with arrays for the first time):
Dim finden As String, FirstFound As String
Dim FoundCell As Range, rng As Range
Dim i As Integer
Dim zahl As Integer
Dim zeile As Range
Dim temparray As Double
Dim b As Integer
Dim count As Integer
Set rng = Worksheets("Tabelle1").Range("H1:H100")
i = Worksheets("Tabelle1").Cells(Rows.count, "D").End(xlUp).Row
For zahl = 1 To i
finden = Sheets("Tabelle1").Cells(zahl, "D").Value
count = Application.WorksheetFunction.CountIf(Range("A1:A100"), finden)
Set zeile = Sheets("Tabelle1").Columns("D").Find(finden, Cells(Rows.count, "D"), xlValues, xlWhole)
If Not zeile Is Nothing Then
FoundCell = zeile.Address
Do
For b = 1 To count
Set temparray(b, 1) = Sheets("Tabelle1").Cells(zeile.Row, "A").Value
Set zeile = Sheets("Tabelle1").Columns("A").Find(finden, zeile, xlValues, xlWhole)
Next b
Loop While zeile.Address <> FoundCell
End If
Set zeile = Nothing
rng.Value = temparray
Sheets("Tabelle1").Cells(1, 8 + zahl) = rng.Value
Next
End Sub
Unfortunately I already get a error message for:
set temparray(b,1)
telling me a data field was expected.
Any idea how I could solve my problem?
Have a look at the Collection object as it is a good way to store unique values. You don't need to run the multiple Find functions or incrementally build your array, you could simply read the columns once and write them into the relevant collection.
It's had to tell from your question and code how you want to write the output, but the code below will set you in the right direction:
Dim uniques As Collection
Dim valueSet As Collection
Dim valueD As String
Dim valueA As String
Dim v As Variant
Dim r As Long
Dim c As Long
Dim output() As String
'Read the data
With ThisWorkbook.Worksheets("Tabelle1")
v = .Range("A1", _
.Cells(Rows.Count, "D").End(xlUp)) _
.Value2
End With
'Populate the collections
Set uniques = New Collection
For r = 1 To UBound(v, 1)
valueA = CStr(v(r, 1))
valueD = CStr(v(r, 4))
'Check if we have a collection for the D value
Set valueSet = Nothing
On Error Resume Next
Set valueSet = uniques(valueD)
On Error GoTo 0
'If not then create a new one.
If valueSet Is Nothing Then
Set valueSet = New Collection
uniques.Add valueSet, Key:=valueD
End If
'Add the A value to it
valueSet.Add valueA
Next
'Compile the write array
ReDim Preserve output(1 To 1, 1 To uniques.Count)
c = 1
For Each valueSet In uniques
For Each v In valueSet
'--> uncomment this 'If block', if you want
'--> comma separated values.
' If Len(output(1, c)) > 0 Then
' output(1, c) = output(1, c) & ", "
' End If
output(1, c) = output(1, c) & v
Next
c = c + 1
Next
'Write the output array
ThisWorkbook.Worksheets("Tabelle1") _
.Range("H1").Resize(, UBound(output, 2)) _
.Value = output
I've been searching for an answer to this, but I haven't been able to find anything specific enough to fill the gap in my VBA knowledge.
I'm putting two lists of data into arrays to be compared using a modified version of the code found here
(I'll post it below).
HOWEVER, I don't want to input the whole cell into the array to be compared with the second array. For instance, if the cell in the first sheet says "Company, LLC", I would like to only search "Company". I have some code that does this:
s = rCell.Value
indexofthey = InStr(1, s, ",")
aftercomma = Right(s, Len(s) - indexofthey + 1)
celld = Left(s, Len(s) - Len(aftercomma))
The code I need to somehow work this into (copied from the answer to the question I linked above) is this:
Option Explicit
Private Sub cmdCompare2to1_Click()
Dim sheet1 As Worksheet, sheet2 As Worksheet, sheet3 As Worksheet
Dim lngLastR As Long, lngCnt As Long
Dim var1 As Variant, var2 As Variant, x
Dim rng1 As Range, rng2 As Range
Set sheet1 = Worksheets(1)
Set sheet2 = Worksheets(2)
Set sheet3 = Worksheets(3) ' assumes sheet3 is a blank sheet in your workbook
Application.ScreenUpdating = False
'let's get everything all set up
'sheet3 column headers
sheet3.Range("A1:B1").Value = Array("in1Not2", "in2Not1")
'sheet1 range and fill array
With sheet1
lngLastR = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng1 = .Range("A1:A" & lngLastR)
var1 = rng1
End With
'sheet2 range and fill array
With sheet2
lngLastR = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng2 = .Range("A1:A" & lngLastR)
var2 = rng2
End With
'first check sheet1 against sheet2
On Error GoTo NoMatch1
For lngCnt = 1 To UBound(var1)
x = Application.WorksheetFunction.Match(var1(lngCnt, 1), rng2, False)
Next
'now check sheet2 against sheet1
On Error GoTo NoMatch2
For lngCnt = 1 To UBound(var2)
x = Application.WorksheetFunction.Match(var2(lngCnt, 1), rng1, False)
Next
On Error GoTo 0
Application.ScreenUpdating = True
Exit Sub
NoMatch1:
sheet3.Range("A" & sheet3.Rows.Count).End(xlUp).Offset(1) = var1(lngCnt, 1)
Resume Next
NoMatch2:
sheet3.Range("B" & sheet3.Rows.Count).End(xlUp).Offset(1) = var2(lngCnt, 1)
Resume Next
End Sub
Assuming you do not want to change the values in your cells you will need to loop through the arrays. You can use a proc like this:
Sub RemoveUnwantedText(ByRef theArray As Variant)
Dim theValue As String
Dim i As Long
Dim indexOfComma As Integer
' array is created from single-column range of cells
' and so has 2 dimensions
For i = LBound(theArray, 1) To UBound(theArray, 1)
theValue = CStr(theArray(i, 1))
indexOfComma = InStr(1, theValue, ",")
If indexOfComma > 0 Then
theValue = Trim(Left(theValue, indexOfComma - 1))
End If
theArray(i, 1) = theValue
Next i
End Sub
Paste this into the same module as your code. In your code, before you do any comparison, add these calls:
RemoveUnwantedText var1
RemoveUnwantedText var2