vba loop no checking for duplicate part number - excel

I need my loop to check for existing part numbers and only if there is no existing part number to add it to my table. If the part number already exists, to have a message box stating that it already exists. Its adding it to my table just fine, but will not give me the message box if there is already an existing part number.
Private Sub Add_Click()
Dim ws As Worksheet
Set ws = Sheet4
Dim X As Integer
Dim lastrow As Long
Dim PartColumnIndex As Integer
Dim DescriptionColumnIndex As Integer
Const Part = "CM ECP"
Const Description = "Material Description"
Dim PartNum As String
Dim MaterailDescription As String
Dim tbl As ListObject
Set tbl = ws.ListObjects("Master")
Dim newrow As ListRow
Set newrow = tbl.ListRows.Add
With ws
On Error Resume Next
Let PartColumnIndex = WorksheetFunction.Match(PartNum, .Rows(2), 0)
Let DescriptionColumnIndex = WorksheetFunction.Match(MaterialDecription, .Rows(2), 0)
Let lastrow = .Cells(.Rows.Count, PartColumnIndex).End(xlUp).Row
X = 3
Do
Let PartValue = .Cells(X, PartColumnIndex).Value
Let DecriptionColumnIndex = .Cells(X, DecriptionColumnIndex).Value
If TextBox1.Value = PartValue Then
MsgBox "Part Number " + TextBox1.Value + " already exists. Please try again or return to main screen."
ElseIf TextBox1.Value <> PartValue Then
With newrow
.Range(1) = TextBox1.Value
.Range(2) = TextBox2.Value
End With
ElseIf X < lastrow Then
X = X + 1
End If
Loop Until X > lastrow
End With

Scan all the rows in the table before deciding to add a new row or not, and always add Use Option Explicit to top of code to catch errors like DecriptionColumnIndex (no s).
Option Explicit
Sub Add_Click()
Const PART = "CM ECP"
Const DESCRIPTION = "Material Description"
Dim ws As Worksheet
Dim X As Integer, lastrow As Long
Dim PartColumnIndex As Integer, DescrColumnIndex As Integer
Dim PartNum As String, MaterialDescription As String
Dim tbl As ListObject, bExists As Boolean
Set ws = Sheet1
Set tbl = ws.ListObjects("Master")
With tbl
PartColumnIndex = .ListColumns(PART).Index
DescrColumnIndex = .ListColumns(DESCRIPTION).Index
PartNum = Trim(TextBox1.Value)
MaterialDescription = Trim(TextBox2.Value)
' search
With .DataBodyRange
lastrow = .Rows.Count
For X = 1 To lastrow
If .Cells(X, PartColumnIndex).Value = PartNum Then
bExists = True
Exit For
End If
Next
End With
' result
If bExists = True Then
MsgBox "Part Number `" & PartNum & "` already exists on Row " & X & vbLf & _
"Please try again or return to main screen.", vbExclamation
Else
With .ListRows.Add
.Range(, PartColumnIndex) = PartNum
.Range(, DescrColumnIndex) = MaterialDescription
End With
MsgBox "Part Number `" & PartNum & "` added", vbInformation
End If
End With
End Sub

Related

Searchable combobox not working with collection

I have a dropdown that before was being populated with values from a second sheet in my workbook using the following code:
Private Sub UserForm_Initialize()
Dim cProd As Range
Dim ws As Worksheet
Dim i As Long
Set ws = ThisWorkbook.Worksheets("DO NOT DELETE")
For Each cProd In ws.Range("ProdList")
With Me.dropProd
.AddItem cProd.Value
End With
Next cProd
Me.dropProd.SetFocus
End Sub
Then, I added the code I found here to add the searchable functionality to it, and it was working just fine.
Then I had to tweak my code to add a second dropdown that would be dependent on the first one that I had previously. To do that, I deleted that DO NOT DELETE worksheet, and created two collections to store the values for the dropdowns.
Now, my first dropdown is being populated in this code:
Sub UpdateAll()
Dim ProdID As String
Dim Prod As String
Dim TF As Boolean
Dim lRow As Long
Dim i, t, s
dropProd.Clear
dropPromo.Clear
Set ws = ThisWorkbook.Worksheets("Table View")
Set cProd = New Collection
lRow = ws.Cells(Rows.Count, 1).End(-4162).Row
For i = 13 To lRow
ProdID = ws.Cells(i, 2).Value
Prod = ws.Cells(i, 3).Value
If ProdID <> "" Then
TF = False
If cProd.Count <> 0 Then
For t = 1 To cProd.Count
If cProd(t) = ProdID & " - " & Prod Then TF = True
Next
End If
If TF = False Then cProd.Add (ProdID & " - " & Prod)
End If
Next
For s = 1 To cProd.Count
dropProd.AddItem (cProd(s))
Next
End Sub
Private Sub UserForm_Initialize()
Me.dropProd.SetFocus
UpdateAll
End Sub
This part is also doing great, the below is where I'm having trouble with:
Private Sub dropProd_Change()
Dim ProdInfo As String
Dim Promo As String
Dim q, p
dropPromo.Clear
lRow = ws.Cells(Rows.Count, 1).End(-4162).Row
If dropProd.Value <> "" Then
ProdInfo = Mid(dropProd.Value, 1, InStr(1, dropProd.Value, " - ") - 1)
End If
'Populates Promo ComboBox
For q = 13 To lRow
Promo = ws.Cells(q, 9).Value
If ws.Cells(q, 2).Value = ProdInfo Then dropPromo.AddItem Promo
Next
End Sub
The above works fine if I just select the value from the dropdown, but it breaks every time I try to search anything, and the problem is in this line ProdInfo = Mid(dropProd.Value, 1, InStr(1, dropProd.Value, " - ") - 1)
I've tried to rewrite it in another way, but it's still throwing me an error. Also, I tried to incorporate the code from the link above to see if it would work, but then I didn't know what to reference on me.dropProd.List = ????. I've tried haing this equals to the Collection I have, and of course it didn't work, and now I'm stuck on how to fix it.
I couldn't reproduce the problem with your code line ProdInfo = Mid(dropProd.Value, 1, InStr(1, dropProd.Value, " - ") - 1), it might be data related. Try this alternative ProdInfo = Trim(Split(dropProd.Value, "-")(0)) and a dictionary rather than a collection.
Option Explicit
Dim ws
Sub UpdateAll()
Dim ProdID As String, Prod As String
Dim lastrow As Long, i As Long
dropProd.Clear
dropPromo.Clear
Dim dictProd As Object, k As String
Set dictProd = CreateObject("Scripting.DIctionary")
Set ws = ThisWorkbook.Worksheets("Table View")
With ws
lastrow = ws.Cells(.Rows.Count, 1).End(xlUp).Row
For i = 13 To lastrow
ProdID = Trim(.Cells(i, 2))
If Len(ProdID) > 0 Then
Prod = Trim(.Cells(i, 3))
k = ProdID & " - " & Prod
If Not dictProd.exists(k) Then
dictProd.Add k, 1
End If
End If
Next
dropProd.List = dictProd.keys
End With
End Sub
Private Sub dropProd_Change()
Dim ProdInfo As String, Promo As String
Dim lastrow As Long, i As Long
dropPromo.Clear
If dropProd.Value <> "" Then
ProdInfo = Trim(Split(dropProd.Value, "-")(0))
'Populates Promo ComboBox
With ws
lastrow = ws.Cells(.Rows.Count, 1).End(xlUp).Row
For i = 13 To lastrow
If .Cells(i, 2).Value = ProdInfo Then
Promo = ws.Cells(i, 9).Value
dropPromo.AddItem Promo
End If
Next
End With
End If
End Sub
Private Sub UserForm_Initialize()
Me.dropProd.SetFocus
UpdateAll
End Sub

Loop Through Shapes in a Workbook and rename based on Location

Long time listener, first time caller.
Anyway, I could use a bit of help. I have a macro that adds Text Boxes, and names them "Fig Num " & ActiveSheet.Shapes.count.
Once all of these text boxes are spread through out the Workbook, I would like to rename all shapes with the name "Fig Num*", or at least the text inside them, to go in order from first page to last, top to bottom, and left to right.
Currently, my code will rename the the text boxes based on seniority. In other words, if I added a text box and it was labeled "Fig Num 3", it would still be named "Fig Num 3" whether it was on the first page or last page.
enter code here
Sub Loop_Shape_Name()
Dim sht As Worksheet
Dim shp As Shape
Dim i As Integer
Dim Str As String
i = 1
For Each sht In ActiveWorkbook.Worksheets
For Each shp In sht.Shapes
If InStr(shp.Name, "Fig Num ") > 0 Then
sht.Activate
shp.Select
shp.Name = "Fig Num"
End If
Next shp
For Each shp In sht.Shapes
If InStr(shp.Name, "Fig Num") > 0 Then
sht.Activate
shp.Select
shp.Name = "Fig Num " & i
Selection.ShapeRange(1).TextFrame2.TextRange.Characters.Text = _
"FIG " & i
i = i + 1
End If
Next shp
Next sht
End Sub
---
I have a workbook example, but I'm not sure how to load it up, this being my first time and all.
Edit:
I have found a code that will do what I'm looking for, however it's a bit clunky. I also need a good way to find the last row on the sheet that contains a shape. Since the shape names are based on creation, if I insert a shape in row 35 and use the shape.count. featured below, it will skip all shapes after row 35 unless I add additional rows that bog down the code.
Most Recent Code (loops through grouped shapes):
Private Sub Rename_FigNum2()
'Dimension variables and data types
Dim sht As Worksheet
Dim shp As Shape
Dim subshp As Shape
Dim i As Integer
Dim str As String
Dim row As Long
Dim col As Long
Dim NextRow As Long
Dim NextRow1 As Long
Dim NextCol As Long
Dim rangex As Range
Dim LR As Long
i = 1
'Iterate through all worksheets in active workbook
For Each sht In ActiveWorkbook.Worksheets
If sht.Visible = xlSheetVisible Then
LR = Range("A1").SpecialCells(xlCellTypeLastCell).row + 200
If sht.Shapes.Count > 0 Then
With sht
NextRow1 = .Shapes(.Shapes.Count).BottomRightCell.row + 200
'NextCol = .Shapes(.Shapes.Count).BottomRightCell.Column + 10
End With
If LR > NextRow1 Then
NextRow = LR
Else
NextRow = NextRow1
End If
End If
NextCol = 15
Set rangex = sht.Range("A1", sht.Cells(NextRow, NextCol))
For row = 1 To rangex.Rows.Count
For col = 1 To rangex.Columns.Count
For Each shp In sht.Shapes
If shp.Type = msoGroup Then
For Each subshp In shp.GroupItems
If Not Intersect(sht.Cells(row, col), subshp.TopLeftCell) Is Nothing Then
If InStr(subshp.Name, "Fig Num") > 0 Then
subshp.Name = "Fig Num " & i
subshp.TextFrame2.TextRange.Characters.Text = _
"FIG " & i
i = i + 1
End If
End If
Next subshp
Else
If Not Intersect(sht.Cells(row, col), shp.TopLeftCell) Is Nothing Then
If InStr(shp.Name, "Fig Num ") > 0 Then
shp.Name = "Fig Num " & i
shp.TextFrame2.TextRange.Characters.Text = _
"FIG " & i
i = i + 1
End If
End If
End If
Next shp
Next col
Next row
End If
Next sht
End Sub
Example of Workbook:
Rename Text Boxes
To use the ArrayList, you have to have .NET Framework 3.5 SP1 installed, even if you already have a later version (e.g. 4.7) installed.
It is assumed that each text box is an ActiveX control (not a Form control) and has a (per worksheet) unique top-left cell.
Option Explicit
Sub RenameTextBoxes()
Const oTypeName As String = "TextBox" ' OLEObject Type Name
Const fPattern As String = "Fig Num " ' Find Pattern (Unsorted)
Const tPattern As String = "Dummy" ' Temporary Pattern
Const nPattern As String = "Fig Num " ' New Pattern (Sorted)
Const ByRows As Boolean = False
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim arl As Object: Set arl = CreateObject("System.Collections.ArrayList")
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim ws As Worksheet
Dim ole As OLEObject
Dim Key As Variant
Dim n As Long
Dim r As Long
Dim Coord As Double
Dim tName As String
For Each ws In wb.Worksheets
arl.Clear
dict.RemoveAll
For Each ole In ws.OLEObjects
If TypeName(ole.Object) = oTypeName Then
If InStr(1, ole.Name, fPattern, vbTextCompare) = 1 Then
n = n + 1
If ByRows Then
Coord = GetNumericByRows(ole.TopLeftCell)
Else
Coord = GetNumericByColumns(ole.TopLeftCell)
End If
arl.Add Coord
tName = tPattern & n
ole.Name = tName
dict(Coord) = tName
End If
End If
Next ole
arl.Sort
For Each Key In arl
r = r + 1
ws.OLEObjects(dict(Key)).Name = nPattern & r
'Debug.Print nPattern & r, Key, dict(Key)
Next Key
Next ws
End Sub
Function GetNumericByColumns( _
ByVal OneCellRange As Range) _
As Double
If OneCellRange Is Nothing Then Exit Function
With OneCellRange.Cells(1)
GetNumericByColumns = Val(.Column & "." & Format(.Row, "000000#"))
End With
End Function
Function GetNumericByRows( _
ByVal OneCellRange As Range) _
As Double
If OneCellRange Is Nothing Then Exit Function
With OneCellRange.Cells(1)
GetNumericByRows = Val(.Row & "." & Format(.Column, "0000#"))
End With
End Function
' Modify the range address to see what the 'GetNumeric' functions are all about.
Sub GetNumericTEST()
Dim cCell As Range: Set cCell = Sheet1.Range("XFD1048576")
Debug.Print GetNumericByColumns(cCell)
Debug.Print GetNumericByRows(cCell)
End Sub

Error handling for Match inside a class - Excel VBA

I have a VBA class that I call to fetch column numbers for the required columns in a worksheet (15 of them). Users are allowed to move columns around and the match functionality works well. However if a user deletes a column, I get a runtime error. How do I trap an error and let the user know that 'X' column name has been deleted but still continue checking the rest of the columns.
Option Explicit
Public EmpName As Long, EmpID As Long, EmpDepartment As Long, EmpAddress As Long
Private Sub Class_Initialize()
Dim ws As Worksheet, r As Range, tStr As String, wsname As String
Set ws = ActiveSheet: Set r = ws.Range("1:1")
EmpName = Application.WorksheetFunction.Match("EmpName", r.value, 0)
EmpID = Application.WorksheetFunction.Match("EmpID", r.value, 0)
EmpDepartment = Application.WorksheetFunction.Match("EmpDepartment", r.value, 0)
EmpAddress = Application.WorksheetFunction.Match("EmpAddress", r.value, 0)
Set r = Nothing: Set ws = Nothing
End Sub
Original code updated
To avoid the run-time error you could use Application.Match instead of Application.WorksheetFunction.Match.
Option Explicit
Public EmpName As Long, EmpID As Long, EmpDepartment As Long, EmpAddress As Long
Private Sub Class_Initialize()
Dim ws As Worksheet, r As Range, tStr As String, wsname As String
Dim Res As Variant
Set ws = ActiveSheet
Set r = ws.Range("1:1")
Res = Application.Match("EmpName", r.Value, 0)
If Not IsError(Res) Then
EmpName = Res
Else
MsgBox "EmpName column not found!", vbInformation, "Missing Column"
End If
Res = Application.Match("EmpID", r.Value, 0)
If Not IsError(Res) Then
EmpID = Res
Else
MsgBox "EmpID column not found!", vbInformation, "Missing Column"
End If
Res = Application.Match("EmpDepartment", r.Value, 0)
If Not IsError(Res) Then
EmpName = Res
Else
MsgBox "EmpDepartment column not found!", vbInformation, "Missing Column"
End If
Res = Application.Match("EmpAddress", r.Value, 0)
If Not IsError(Res) Then
EmpAddress = Res
Else
MsgBox "EmpAddress column not found!", vbInformation, "Missing Column"
End If
End Sub
Using a dictionary
If you don't want all the repetition in the code you might want to look at using a dictionary to store the column names/numbers.
Option Explicit
Private Sub Class_Initialize()
Dim ws As Worksheet, r As Range, tStr As String, wsname As String
Dim dicCols As Object
Dim arrCols As Variant
Dim Res As Variant
Dim idx As Long
arrCols = Array("EmpName", "EmpID", "EmpDepartmen", "EmpAddress")
Set dicCols = CreateObject("Scripting.Dictionary")
Set ws = ActiveSheet
Set r = ws.Range("1:1")
For idx = LBound(arrCols) To UBound(arrCols)
Res = Application.Match(arrCols(idx), r.Value, 0)
If Not IsError(Res) Then
dicCols(arrCols(idx)) = Res
Else
dicCols(arrCols(idx)) = "Not Found"
MsgBox arrCols(idx) & " column not found!", vbInformation, "Missing Column"
End If
Next idx
End Sub
Once this code is executed you can use dicCols(ColumnName) to get the column number.
For example, wherever you refer to the variable EmpName in the rest of the code you can use dicCols("EmpName").
Using a dictionary populated from a function
Another refinement might be to use a function to create the dictionary.
This would allow you to pass different sets of column names when required.
Option Explicit
Public dicCols As Object
Private Sub Class_Initialize()
Dim ws As Worksheet, r As Range, tStr As String, wsname As String
Dim arrColNames As Variant
Dim arrNotFound() As Variant
Dim ky As Variant
Dim cnt As Long
arrColNames = Array("EmpName", "EmpID", "EmpDepartment", "EmpAddress")
Set ws = ActiveSheet
Set r = ws.Range("1:1")
Set dicCols = GetColNos(arrColNames, r)
For Each ky In dicCols.keys
If dicCols(ky) = "Not Found" Then
cnt = cnt + 1
ReDim Preserve arrNotFound(1 To cnt)
arrNotFound(cnt) = ky
End If
Next ky
If cnt > 0 Then
MsgBox "The following columns were not found:" & vbCrLf & vbCrLf & Join(arrNotFound, vbCrLf), vbInformation, "Missing Columna"
End If
End Sub
Function GetColNos(arrColNames, rngHdr As Range) As Object
Dim dic As Object
Dim idx As Long
Dim Res As Variant
Set dic = CreateObject("Scripting.Dictionary")
For idx = LBound(arrColNames) To UBound(arrColNames)
Res = Application.Match(arrColNames(idx), rngHdr.Value, 0)
If Not IsError(Res) Then
dic(arrColNames(idx)) = Res
Else
dic(arrColNames(idx)) = "Not Found"
End If
Next idx
Set GetColNos = dic
End Function

Excel VBA Code pastes result into wrong range

A script that copies a range into another range. However, when I try to copy the range from Sheet1 to Sheet2 the result won't be pasted into column J, it get pasted with an offset of 8 columns (column R). I cant understand why? Both RowCountSummary and ColumnCountSummary are set to 0, i.e. first index of the range?
Sub InsertForecastData()
Dim ColumnsCount As Integer
Dim ColCounter As Integer
Dim RowsCount As Integer
Dim ForeCastRange As Range
Dim ForecastWS As Worksheet
Dim SummaryWs As Worksheet
Dim PasteRange As Range
Dim ColumnCountSummary As Integer
Dim RowCountSummary As Integer
ColumnsCount = 300
ColCounter = 0
RowsCount1 = 0
RowsCount2 = 47
ColumnCountSummary = 0
RowCountSummary = 0
Do While ColCounter <= ColumnsCount
Worksheets("Sheet1").Select
Set ForeCastRange = Worksheets("Sheet1").Range("B2:KN49")
With ForeCastRange
.Range(.Cells(RowsCount1, ColCounter), .Cells(RowsCount2, ColCounter)).Copy
End With
Worksheets("Sheet2").Select
Set PasteRange = Worksheets("Sheet2").Range("J2:J13915")
With PasteRange
.Range(.Cells(RowCountSummary, ColumnCountSummary), .Cells(RowCountSummary + RowsCount2, ColumnCountSummary)).PasteSpecial
End With
RowCountSummary = RowCountSummary + 48
ColCounter = ColCounter + 1
Loop
End Sub
This behaviour has been encountered before and can seen with this simple demo
Sub test()
With Sheet1.Range("J3:J100")
Debug.Print .Range(.Cells(0, 0), .Cells(47, 0)).Address
End With
End Sub
which results in $R$4:$R$51. If you repeat run for the columns B to J the results are B,D,F,H,J,L,N,P showing the doubling effect. B is OK I think because of the zero column number.
You can probably fix your code by setting RowCountSummary = 1 and ColumnCountSummary = 1 and adding .parent
With PasteRange
.Parent.Range(.Cells(RowCountSummary, ColumnCountSummary), _
.Cells(RowCountSummary + RowsCount2, ColumnCountSummary)).PasteSpecial
End With
or you could try this
Sub InsertForecastData1()
Const columnCount As Integer = 3
Const rowCount As Integer = 48
Const sourceCol As String = "B"
Const targetCol As String = "J"
Const startRow As Integer = 2
Const records As Integer = 300
Dim rngSource as Range, rngTarget As Range
Dim start as Single, finish as Single
Set rngSource = Worksheets("Sheet1").Range(sourceCol & startRow)
Set rngSource = rngSource.Resize(rowCount, columnCount)
Set rngTarget = Worksheets("Sheet2").Range(targetCol & startRow)
start = Timer
Application.ScreenUpdating = False
Dim i As Integer
For i = 1 To records
'Debug.Print rngSource.Address, rngTarget.Address
rngSource.Copy rngTarget
Set rngSource = rngSource.Offset(rowCount, 0)
Set rngTarget = rngTarget.Offset(rowCount, 0)
Next i
Application.ScreenUpdating = True
finish = Timer
MsgBox "Completed " & records & " records in " & finish - start & " secs"
End Sub
See Remarks section the docs

VBA Excel remove Items unique to one sheet

I'm working on a long application and I hit a wall trying to find unique records between 2 sheets and removing the row from the first sheet if the record doesn't exist in the second sheet. Here's the code I have for this section of my program, I'm a bit confuse as to how to accomplish this and I'm hoping someone will be willing to take a look and give me some suggestions, thanks.
*Explanation:
I'm looking for the unique records in column B and I'll be searching over 3000 cells in that column. If the records exist in sheet 1 but not in sheet 2 they should be deleted.
Option Explicit
Sub RemoveReversionItems()
Dim wbook As Workbook, Wsheet As Worksheet, wbName As String, wsName As String
Dim AlphaRange As Range, ReversionRange As Range
Dim AlphaArray
Dim ReversionArray
Dim x As Long
Dim AlphaSheetColumn As String: AlphaSheetColumn = "B" 'The column with the PO#
Dim ReversionSheetColumn As String: ReversionSheetColumn = "B" 'The column with the PO#
For Each wbook In Workbooks
If wbook.Name <> ActiveWorkbook.Name Then wbName = wbook.Name
Workbooks(wbName).Activate
'********************************
' Look for Reversion Queue
'********************************
For Each Wsheet In wbook.Worksheets
wsName = Wsheet.Name
If Wsheet.Name Like "Revers*" Then
MsgBox "This workbook is named " & wbName & " The Sheet is " & wsName
'Get Reversion Range
With Sheets(wsName)
Set ReversionRange = .Range(.Range(ReversionSheetColumn & "2"), _
.Range(ReversionSheetColumn & rows.Count).End(xlUp))
ReversionArray = ReversionRange
End With
End If
Next Wsheet
'*****************************
' Look for Alpha Queue
'*****************************
For Each Wsheet In wbook.Worksheets
wsName = Wsheet.Name
If Wsheet.Name Like "PO_LN*" Then
'Load Alpha WorkSheet array
With Sheets(wsName)
Set AlphaRange = .Range(.Range(AlphaSheetColumn & "2"), _
.Range(AlphaSheetColumn & rows.Count).End(xlUp))
AlphaArray = AlphaRange
End With
MsgBox "This workbook is named " & wbName & " The Sheet is " & wsName
End If
Next Wsheet
If IsArray(ReversionArray) Then
For x = UBound(ReversionArray) To 1 Step -1
If AlphaArray <> ReversionArray(x, 2) Then
ReversionRange.Cells(x).EntireRow.Interior.Color = 255 'Newtest
End If
Next
Else
End If
Next wbook
End Sub
This function compares 2 data sheets with the same columns based on a primary key. It will highlight non-matched rows in orange and where the rows do match it will find any differences in the field values and highlight red and create a comment to show mismatched value (you can always removed this functionality)
Just pass in the 2 sheet names, the primary key col and whether data has col headers.
eg. strResult=CompareDataSheets("Sheet1","Sheet2",1,True)
Function CompareDataSheets(ByVal sht1 As String, ByVal sht2 As String, ByVal pkCol As Integer, ByVal hasHeaders As Boolean) As String
Dim ws1, ws2 As Worksheet
Dim x As Integer
Dim nmSht1, nmSht2, colDiffs, colName As String
Dim strIdentifier As String
Dim vmatch As Variant
Set ws1 = ActiveWorkbook.Sheets(sht1)
Set ws2 = ActiveWorkbook.Sheets(sht2)
On Error GoTo Err
If hasHeaders Then x = 2 Else x = 1
'Find Non Matches in sheet1
Do Until ws1.Cells(x, pkCol).Value = ""
vmatch = Application.Match(ws1.Cells(x, pkCol).Value, ws2.Columns(pkCol), 0)
If IsError(vmatch) Then
ws1.Rows(x).Interior.Color = 49407
Else
'Find Matched PK Column diffs
iCol = 1
Do Until ws1.Cells(1, iCol).Value = ""
If ws1.Cells(x, iCol).Value <> ws2.Cells(x, iCol).Value Then
If hasHeaders Then
colName = ws1.Cells(1, iCol).Value
Else
colName = iCol
End If
With ws1.Cells(x, iCol)
.Interior.Color = 5263615
.ClearComments
.AddComment sht2 & " Value=" & ws2.Cells(x, iCol).Value
End With
If ws2.Cells(x, iCol).Value <> "" Then
With ws2.Cells(x, iCol)
.Interior.Color = 5263615
.ClearComments
.AddComment sht1 & " Value=" & ws1.Cells(x, iCol).Value
End With
End If
End If
iCol = iCol + 1
Loop
End If
x = x + 1
Loop
If Len(nmSht1) > 0 Then nmSht1 = Left(nmSht1, Len(nmSht1) - 1)
If hasHeaders Then x = 2 Else x = 1
'Find Non Matches in sheet2
Do Until ws2.Cells(x, pkCol).Value = ""
vmatch = Application.Match(ws1.Cells(x, pkCol).Value, ws2.Columns(pkCol), 0)
If IsError(vmatch) Then
ws2.Rows(x).Interior.Color = 49407
End If
x = x + 1
Loop
If Len(nmSht2) > 0 Then nmSht2 = Left(nmSht2, Len(nmSht2) - 1)
CompareDataSheets = "Done!"
Exit Function
Err:
CompareDataSheets = "Error: " & Err.Description
End Function

Resources