How to make the for loop merge new values across sheets? - vba

I had someone help me make the initial code for this, Im trying to modify it however its wrong.
I need to compare sheet 2 in a spreadsheet to sheets 4 to 10 and if the values of row e or b do not match any other row. copy the entire row to the bottom of sheet 1.
This is what I have so far but the value isn't being set to true and it prints after every sheet. I'm stick
Sub Button13() 'merge
Dim lastSourceRow As Long, LastTargetRow As Long, allSheets As Long, lastSheet As Long
Dim source As String, TARGET As Integer
Dim tempVal As String, tempValE, tempValT
Dim tRow As Long, lRow As Long, lCol As Long, nRow As Long
Dim match As Boolean
source = "Sheet2"
lastSheet = "10"
lastSourceRow = Sheets(source).Range("A" & Rows.Count).End(xlUp).Row
For allSheets = 1 To lastSheet
TARGET = allSheets
LastTargetRow = Sheets(TARGET).Range("A" & Rows.Count).End(xlUp).Row
For lRow = 2 To lastSourceRow 'Loop through Rows on currentsheet
Count = "0"
match = False 'Reset boolean test for each new row
tempVal = Sheets(source).Cells(lRow, "B").Value 'Assign the tempValue to compare
tempValE = Sheets(source).Cells(lRow, "E").Value
For tRow = 2 To LastTargetRow 'Loop through entire target sheet
tempValT = Sheets(TARGET).Cells(tRow, "B").Value
If (allSheets <> 2 Or allSheets <> 3) And tempVal = Sheets(TARGET).Cells(tRow, "B").Value And tempValE = Sheets(TARGET).Cells(tRow, "E").Value Then
match = True
ElseIf (allSheets <> 2 Or allSheets <> 3) And tempVal = Sheets(TARGET).Cells(tRow, "B").Value And tempValE = "" Then
match = True
ElseIf (allSheets <> 2 Or allSheets <> 3) And tempVal = Sheets(TARGET).Cells(tRow, "B").Value Then
match = True
'ElseIf Sheets(TARGET).Cells(tRow, "G").Value < DateAdd("m", -5, Date) Then
'match = True
End If
Next tRow
If match = False Then 'No Match found, copy row
nRow = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row + 1
For lCol = 1 To 26 'Copy entire row by looping through 6 columns
Sheets("Sheet1").Cells(nRow, lCol).Value = Sheets(source).Cells(lRow, lCol).Value
Next lCol
End If
Next lRow
Next allSheets
End Sub

You have 2 problems:
problem 1: you reset match = False inside the lRow loop, this must be inside the tRow loop, otherwise if the first match = True hits then match is never reset
problem 2: If match = False Then can't be entered because it is outside of your tRow loop. so match is set inside the loop but can not be reached by If match = False Then
so the working code should be
Sub Button13() 'merge
Dim lastSourceRow As Long, LastTargetRow As Long, allSheets As Long, lastSheet As Long
Dim source As String, TARGET As Integer
Dim tempVal As String, tempValE, tempValT
Dim tRow As Long, lRow As Long, lCol As Long, nRow As Long
Dim match As Boolean
source = "Sheet2"
lastSheet = "10"
lastSourceRow = Sheets(source).Range("A" & Rows.Count).End(xlUp).Row
For allSheets = 1 To lastSheet
TARGET = allSheets
LastTargetRow = Sheets(TARGET).Range("A" & Rows.Count).End(xlUp).Row
For lRow = 2 To lastSourceRow 'Loop through Rows on currentsheet
Count = "0"
tempVal = Sheets(source).Cells(lRow, "B").Value 'Assign the tempValue to compare
tempValE = Sheets(source).Cells(lRow, "E").Value
For tRow = 2 To LastTargetRow 'Loop through entire target sheet
tempValT = Sheets(TARGET).Cells(tRow, "B").Value
If (allSheets <> 2 Or allSheets <> 3) And tempVal = Sheets(TARGET).Cells(tRow, "B").Value And tempValE = Sheets(TARGET).Cells(tRow, "E").Value Then
match = True
ElseIf (allSheets <> 2 Or allSheets <> 3) And tempVal = Sheets(TARGET).Cells(tRow, "B").Value And tempValE = "" Then
match = True
ElseIf (allSheets <> 2 Or allSheets <> 3) And tempVal = Sheets(TARGET).Cells(tRow, "B").Value Then
match = True
'ElseIf Sheets(TARGET).Cells(tRow, "G").Value < DateAdd("m", -5, Date) Then
'match = True
End If
If match = False Then 'No Match found, copy row
nRow = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row + 1
For lCol = 1 To 26 'Copy entire row by looping through 6 columns
Sheets("Sheet1").Cells(nRow, lCol).Value = Sheets(source).Cells(lRow, lCol).Value
Next lCol
End If
'2 moved lines
match = False 'Reset boolean test for each new row
Next tRow
Next lRow
Next allSheets
End Sub

Related

Excel Macro - Remove rows and then relabel a cell value

What I'm trying to do is remove any rows where a cell value in a specific column matches what is defined to remove. After that is done re-sequence the value in another column by group.
Using the example below:
I want to look at column B and remove any rows that have a value of A or C. Then I want to basically renumber after the dot (.) in column A to reset itself.
Before Macro Code Fig. 1
After value A and C are removed Fig. 2
Final list after column A is renumbered Fig. 3
I figured out how to remove the rows using this code, but stuck on what to do next:
Sub DeleteRowBasedOnCriteriga()
Dim RowToTest As Long
For RowToTest = Cells(Rows.Count, 2).End(xlUp).Row To 2 Step -1
With Cells(RowToTest, 2)
If .Value = "A" Or .Value = "C" _
Then _
Rows(RowToTest).EntireRow.Delete
End With
Next RowToTest
End Sub
This will be easier to do looping from the top down (using step 1 instead of step -1). I've tried to stay true to your original coding and made this:
Sub DeleteRowBasedOnCriteriga()
Dim RowToTest As Long
Dim startRow As Long
Dim i As Integer
startRow = 2
'Clear the rows that have "A" or "C" in column B
For RowToTest = Cells(Rows.Count, 1).End(xlUp).Row to startRow To Step -1
With Cells(RowToTest, 2)
If .Value = "A" Or .Value = "C" _
Then _
Rows(RowToTest).EntireRow.Delete
End With
Next RowToTest
'If the left 3 characters of the cell above it are the same,_
'then increment the renumbering scheme
For RowToTest = startRow To Cells(Rows.Count, 1).End(xlUp).Row
If Left(Cells(RowToTest, 1).Value, InStr(1, Cells(RowToTest, 1), "\")) = Left(Cells(RowToTest, 1).Offset(-1, 0).Value, InStr(1, Cells(RowToTest, 1), "\")) Then
i = i + 1
Cells(RowToTest, 1).Value = Left(Cells(RowToTest, 1).Value, InStr(1, Cells(RowToTest, 1), ".")) & i
Else
i = 0
Cells(RowToTest, 1).Value = Left(Cells(RowToTest, 1).Value, InStr(1, Cells(RowToTest, 1), ".")) & i
End If
Next RowToTest
End Sub
EDIT: I've updated it to compare all of the string before the backslash and compare using that.
EDIT++: It has been brought to my attention that when deleting rows it is better to work from the bottom up (step -1) to ensure every row is accounted for. I've re-implemented the original steps in the first code.
Admittedly, this isn't probably the most efficient, but it should work.
Sub DeleteRowBasedOnCriteriga()
Dim RowToTest As Long, i As Long
Application.ScreenUpdating = False
For RowToTest = Cells(Rows.Count, 2).End(xlUp).Row To 2 Step -1
With Cells(RowToTest, 2)
If .Value = "A" Or .Value = "C" Then Rows(RowToTest).EntireRow.Delete
End With
Next RowToTest
Dim totalRows As Long
totalRows = Cells(Rows.Count, 1).End(xlUp).Row
Dim curCelTxt As String, aboveCelTxt As String
For i = totalRows To i Step -1
If i = 1 Then Exit For
curCelTxt = Left(Cells(i, 1), WorksheetFunction.Search("\", Cells(i, 1)))
aboveCelTxt = Left(Cells(i - 1, 1), WorksheetFunction.Search("\", Cells(i - 1, 1)))
If curCelTxt = aboveCelTxt Then
Cells(i, 1).Value = ""
Else
Cells(i, 1).Value = WorksheetFunction.Substitute(Cells(i, 1), Right(Cells(i, 1), Len(Cells(i, 1)) - WorksheetFunction.Search(".", Cells(i, 1))), "0")
End If
Next i
Dim rng As Range, cel As Range
Dim tempLastRow As Long
Set rng = Range("A1:A" & Cells(Rows.Count, 2).End(xlUp).Row)
For Each cel In rng
If cel.Offset(1, 0).Value = "" Then
tempLastRow = cel.End(xlDown).Offset(-1, 0).Row
If tempLastRow = Rows.Count - 1 Then
tempLastRow = Cells(Rows.Count, 2).End(xlUp).Row
cel.AutoFill Destination:=Range(cel, Cells(tempLastRow, 1))
Exit For
Else
cel.AutoFill Destination:=Range(cel, Cells(tempLastRow, 1))
End If
End If
Next cel
Application.ScreenUpdating = True
End Sub
Mainly, I discovered that you can use AutoFill to fix the last number in the string. Meaning if you AutoFill this text, CAT\Definitions.0 down, you get the number updating as you drag/fill.

Excel UDF works when called through sub but always returns 0 in worksheet

My function is always returning 0 when called in a worksheet but returns proper values when called through a sub.
This function searches through a worksheet (sheetname) to see if the input value can be found in any of the columns, and if so returns the value in row 1 of the column.
'test sub
Sub test()
MsgBox custCat("SUNTRUST BANK")
End Sub
Public Function custCat(toSearch)
Dim sheetName As String
sheetName = "LookupValues"
Dim i As Integer
i = 1
Dim lastRow As Integer
Dim colLtr As String
Dim j As Integer
'find last column
Dim lastColumn As Integer
lastColumn = Worksheets(sheetName).Range("A1").SpecialCells(xlCellTypeLastCell).Column
'loop through columns
Do While i <= lastColumn
'find last row
lastRow = Worksheets(sheetName).Cells(Worksheets(sheetName).Rows.Count, i).End(xlUp).Row
'search through column
j = 2
Do While j <= lastRow
If InStr(UCase(toSearch), UCase(Worksheets(sheetName).Cells(j, i).Value)) > 0 Then
If custCat = "" Then
custCat = Worksheets(sheetName).Cells(1, i).Value
Else
custCat = custCat & ", " & Worksheets(sheetName).Cells(1, i).Value
End If
j = lastRow 'exit loop if found
End If
j = j + 1
Loop
i = i + 1
Loop
End Function
I cleaned up the code a bit and made a few adjustments, try this:
Public Function custCat(toSearch)
Dim i&, j&, lastRow&, lastColumn&
Dim ws As Worksheet
Set ws = Worksheets("LookupValues")
With ws
lastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
i = 1
'loop through columns
Do While i <= lastColumn
'find last row
lastRow = .Cells(.Rows.Count, i).End(xlUp).Row
'search through column
j = 2
Do While j <= lastRow
If InStr(UCase(toSearch), UCase(.Cells(j, i).Value)) > 0 Then
If custCat = "" Then
custCat = .Cells(1, i).Value
Else
custCat = custCat & ", " & .Cells(1, i).Value
End If
Exit Do 'exit loop if found
End If
j = j + 1
Loop
i = i + 1
Loop
End With
End Function

How to achieve cell copy to the last row in excel using vba?

I want to copy the data present in A9, up to the cell A12 & similarly from B9 to B12. I can copy the data present in cell A1, up to A8 successfully. But cannot copy & paste from A9 to A12 & B9 to B12. My code is unable to copy & paste for the last record.
With wrdApp
.ActiveDocument.Tables(1).Select
.Selection.Copy
With ThisWorkbook.Worksheets("Sheet1")
.Cells(Rows.Count, "C").End(xlUp)(1).PasteSpecial xlPasteValues
'getting the last row
lastRow = .Range("C:C").End(xlDown).row
'loop all row in column "C" for checking
For row = 1 To lastRow Step 1
'If value of C cell is "Version", check column A cell and B cell
If (.Range("C" & row) = "Version" Or .Range("C" & row) = "version") Then
'If both cell are empty, store value.
If .Range("A" & row) = "" And .Range("B" & row) = "" Then
.Range("A" & row).Value = resultId
.Range("B" & row).Value = resultIdZ
LR = Range("B" & Rows.Count).End(xlUp).row
With Range("B2:B" & LR)
With .SpecialCells(xlCellTypeBlanks)
End With
.Value = .Value
End With
LR = Range("A" & Rows.Count).End(xlUp).row
With Range("A2:A" & LR)
With .SpecialCells(xlCellTypeBlanks)
.FormulaR1C1 = "=R[-1]C"
End With
.Value = .Value
End With
Exit For
End If
End If
Next row
End With
You should try this. It pastes the values in A and B that are in the row next to were there is Version in column C as long as column C is not equal to version, and when it equals version it jumps to the next set of data.
It works now, it had a problem when it was in the row that had version in it and had columns a and b filled with data. Now it works:
For row = 1 To lastRow Step 1
'If value of C cell is "Version", check column A cell and B cell
If Cells(row, 3) = "Version" Or Cells(row, 3) = "version" Then
For row2 = row To lastRow
'If both cell are empty and C is not version, store value.
If row2 = row Then
Else
If Cells(row2, 3) <> "Version" And Cells(row2, 3) <> "version" And Cells(row2, 1) = "" And Cells(row2, 2) = "" Then
Cells(row2, 1) = Cells(row, 1)
Cells(row2, 2) = Cells(row, 2)
ElseIf Cells(row2, 3) = "Version" Or Cells(row2, 3) = "version" Then
row = row2 - 1
Exit For
End If
End If
Next row2
End If
Next row
Before:
After
Now inside your code:
With wrdApp
.ActiveDocument.Tables(1).Select
.Selection.Copy
With ThisWorkbook.Worksheets("Sheet1")
.Cells(Rows.Count, "C").End(xlUp)(1).PasteSpecial xlPasteValues
'getting the last row
lastRow = .Range("C:C").End(xlDown).row
'loop all row in column "C" for checking
For row = 1 To lastRow Step 1
'If value of C cell is "Version", check column A cell and B cell
If Cells(row, 3) = "Version" Or Cells(row, 3) = "version" Then
For row2 = row To lastRow
'If both cell are empty and C is not version, store value.
If row2 = row Then
Else
If Cells(row2, 3) <> "Version" And Cells(row2, 3) <> "version" And Cells(row2, 1) = "" And Cells(row2, 2) = "" Then
Cells(row2, 1) = Cells(row, 1)
Cells(row2, 2) = Cells(row, 2)
ElseIf Cells(row2, 3) = "Version" Or Cells(row2, 3) = "version" Then
row = row2 - 1
Exit For
End If
End If
Next row2
End If
Next row
End With
Here is my answer which might help someone.
Prior to that, I would like to say thanks to Luuklag for helping me in a brilliant way.
Make sure that, you add the below references before proceeding.
Option Explicit
Dim FSO As Object
Dim strFolderName As String
Dim FileToOpenVdocx As String
Dim FileToOpenvdoc1 As String
Dim FileToOpenVdoc As String
Dim FileToOpenvdocx1 As String
Dim wrdApp As Word.Application
Dim wrdDoc As Word.Document
Dim fsoFolder As Object
'To copy data from word to excel
'Copy data from word to excel
Sub FindFilesInSubFolders()
Dim fsoFolder As Scripting.Folder
Sheets("Sheet1").Cells.Clear
FileToOpenVdocx = "*V2.1.docx*"
FileToOpenvdoc1 = "*v2.1.doc*"
FileToOpenVdoc = "*V2.1.doc*"
FileToOpenvdocx1 = "*v2.1.docx*"
If FSO Is Nothing Then
Set FSO = CreateObject("Scripting.FileSystemObject")
End If
'Set the parent folder for the new subfolders
strFolderName = "C:\Test1"
Set fsoFolder = FSO.GetFolder(strFolderName)
Set wrdApp = CreateObject("Word.Application")
OpenFilesInSubFolders fsoFolder
wrdApp.Quit
End Sub
Sub OpenFilesInSubFolders(fsoPFolder As Scripting.Folder)
Dim fsoSFolder As Scripting.Folder
Dim fileDoc As Scripting.File
Dim wrdRng As Object
Dim strText As String
Dim singleLine As Object
Dim outRow As Long ' newly added
Dim Found As String
Dim resultId As String
Dim singleLineZ As Object
Dim resultIdZ As String
Dim row As Long
Dim startRow As Long
Dim lastRow As Long
Dim LRA As Long
Dim LRB As Long
Dim row2 As Long
outRow = 1 'you appear to want to start at the first row
For Each fsoSFolder In fsoPFolder.SubFolders
For Each fileDoc In fsoSFolder.Files
If (fileDoc.Name Like FileToOpenVdocx Or fileDoc.Name Like FileToOpenvdoc1 Or fileDoc.Name Like FileToOpenVdoc Or fileDoc.Name Like FileToOpenvdocx1) And Left(fileDoc.Name, 1) <> "~" Then
Set wrdDoc = wrdApp.Documents.Open(fileDoc.Path)
Set wrdRng = wrdDoc.Content
For Each singleLine In wrdApp.ActiveDocument.Paragraphs
Found = InStr(singleLine, "Application")
If Found > 0 Then
resultId = singleLine
Exit For
End If
Next singleLine
For Each singleLineZ In wrdApp.ActiveDocument.Paragraphs
Found = InStr(singleLineZ, "Z")
If Found > 0 Then
resultIdZ = singleLineZ
Exit For
End If
Next singleLineZ
With wrdApp
.ActiveDocument.Tables(1).Select
.Selection.Copy
With ThisWorkbook.Worksheets("Sheet1")
startRow = .Cells(.Rows.Count, "C").End(xlUp)(2).row
.Cells(startRow, "C").PasteSpecial xlPasteValues
lastRow = .Cells(.Rows.Count, "C").End(xlUp).row
'Match the last pasted table with the labels
.Range(.Cells(startRow, "A"), .Cells(lastRow, "A")).Value = resultId
.Range(.Cells(startRow, "B"), .Cells(lastRow, "B")).Value = resultIdZ
End With
End With
wrdDoc.Close False
End If
Next fileDoc
OpenFilesInSubFolders fsoSFolder
Next fsoSFolder
End Sub

VBA - Compare Cell Values In Multiple Work Sheets

I've tasked myself with building a small QA tool, but the problem is that I'm not terribly familiar with VBA or programming. I want to be able to iterate through a single column within three different .csv files. The cells in these columns should match, and the whole point of the tool is to identify the cells that are the "odd man out".
Currently I have some spaghetti code that's giving me an error "false.xlsx" not found...please be gentle...
Sub CompareLists()
Dim count As Integer
Dim kRange As Range
Dim LastRow As Long
Dim iRow As Long
Dim varSheetA As Variant
Dim varSheetB As Variant
Dim varSheetC As Variant
LastRow = Range("A" & Rows.count).End(xlUp).Row
Set kRange = ActiveSheet.Range("A3:A" & LastRow)
Set File_Path1 = Workbooks.Open(Filename = "C:\Test Files\Test_File1.csv")
Set varSheetA = File_Path1.Worksheets("Sheet1").Range(kRange)
Set File_Path2 = Workbooks.Open(Filename = "C:\Test Files\Test_File2.csv")
Set varSheetB = File_Path2.Worksheets("Sheet1").Range(kRange)
Set File_Path3 = Workbooks.Open(Filename = "C:\Test Files\Test_File3.csv")
Set varSheetC = File_Path3.Worksheets("Sheet1").Range(kRange)
For iRow = LBound(varSheetA) To UBound(varSheetA)
count = 1
If varSheetA(iRow) = varSheetB(iRow) Then
count = count + 1
Else
If varSheetA(iRow) = varSheetC(iRow) Then
count = count + 1
Else
If count < 3 Then
ActiveCell.Interior.ColorIndex = 3
End If
End If
End If
Next
End Sub
Your line:
Set File_Path1 = Workbooks.Open(Filename = "C:\Test Files\Test_File1.csv")
Evaluates the inside as a boolean check of whether some nonexistent Filename variable has the value "C:\Test Files\Test_File1.csv". Since the new variable Filename has no value, the comparison returns false. You were probably trying to do := and not =. The := operator assigns to a method parameter while = either does a boolean evaluation or variable assignment. Any one of the following four lines should fix your error as the first use the := operator to assign to the Filename parameter and the last two just know that Filename is the default first parameter.
Set File_Path1 = Workbooks.Open(Filename:="C:\Test Files\Test_File1.csv")
Set File_Path1 = Workbooks.Open Filename:="C:\Test Files\Test_File1.csv"
Set File_Path1 = Workbooks.Open("C:\Test Files\Test_File1.csv")
Set File_Path1 = Workbooks.Open "C:\Test Files\Test_File1.csv"
As a side note, this is something to be very careful about in VBA. Put Option Explicit at the top of every module so that it forces you to define your variables. If you do that, your erroring out line would have complained that variable 'Filename' was not defined.
As far as your next line goes:
Set varSheetA = File_Path1.Worksheets("Sheet1").Range(kRange)
you have two problems. First, when opening a csv file the tab name is always the same as the filename and NOT Sheet1. Second, kRange is part of the worksheet you started on so to get the comparable range on the new sheet you should use kRange.Address. Those fixes change the above into:
Set varSheetA = File_Path1.Worksheets("Test_File1").Range(kRange.Address)
Your loop treats ranges like arrays. The most direct way to fix that is to force them to be arrays by changing the Dim statements (adding parentheses) and the assignment statements for your range variables (removing Set and adding .Value).
Dim varSheetA() As Variant
...
varSheetA = File_Path1.Worksheets("Test_File1").Range(kRange.Address).Value
...
If varSheetA(iRow, 1) = varSheetB(iRow, 1) Then
The best alternative method is to never create the range variables in the first place and just grab cells by row and column indices.
Sub CompareLists_2()
Dim count As Integer
Dim LastRow As Long, iRow As Long
Dim MainSht As Worksheet, ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet
Set MainSht = ActiveSheet
LastRow = MainSht.Range("A" & Rows.count).End(xlUp).Row
Set ws1 = Workbooks.Open(Filename:="C:\Test Files\Test_File1.csv").Worksheets("Test_File1")
Set ws2 = Workbooks.Open(Filename:="C:\Test Files\Test_File2.csv").Worksheets("Test_File2")
Set ws3 = Workbooks.Open(Filename:="C:\Test Files\Test_File3.csv").Worksheets("Test_File3")
For iRow = 3 To LastRow
count = 1
If ws1.Cells(iRow, 1).Value = ws2.Cells(iRow, 1).Value Then
count = count + 1
Else
If ws1.Cells(iRow, 1).Value = ws3.Cells(iRow, 1).Value Then
count = count + 1
Else
If count < 3 Then
MainSht.Cells(iRow, 1).Interior.ColorIndex = 3
End If
End If
End If
Next
End Sub
Of course as far as I can tell your boolean logic reduces to:
If ws1.Cells(iRow, 1).Value <> ws2.Cells(iRow, 1).Value And ws1.Cells(iRow, 1).Value <> ws3.Cells(iRow, 1).Value And ws2.Cells(iRow, 1).Value <> ws3.Cells(iRow, 1).Value Then
MainSht.Cells(iRow, 1).Interior.ColorIndex = 3
End If
Revision of boolean logic per comments (though I'm slightly confused on the logic):
If ws1.Cells(iRow, 1).Value <> ws2.Cells(iRow, 1).Value And ws1.Cells(iRow, 1).Value <> ws3.Cells(iRow, 1).Value And ws2.Cells(iRow, 1).Value <> ws3.Cells(iRow, 1).Value Then
ws1.Cells(iRow, 1).Interior.ColorIndex = 3
ElseIf ws1.Cells(iRow, 1).Value = ws2.Cells(iRow, 1).Value And ws1.Cells(iRow, 1).Value <> ws3.Cells(iRow, 1).Value Then
ws1.Cells(iRow, 1).Interior.ColorIndex = 3
ws2.Cells(iRow, 1).Interior.ColorIndex = 3
End If
Sub CompareLists()
Dim count As Integer
Dim LastRow As Long, iRow As Long
Dim MainSht As Worksheet, ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet, ws4 As Worksheet
Dim ws5 As Workbook
Dim var1 As Variant
Set ws1 = Workbooks.Open(Filename:="C:\Test Files\Test_File1.csv").Worksheets("Test_File1")
Set ws2 = Workbooks.Open(Filename:="C:\Test Files\Test_File2.csv").Worksheets("Test_File2")
Set ws3 = Workbooks.Open(Filename:="C:\Test Files\Test_File3.csv").Worksheets("Test_File3")
Set MainSht = ws1
LastRow = MainSht.Range("A" & Rows.count).End(xlUp).Row
For iRow = 3 To LastRow
count = 1
If ws1.Cells(iRow, 1).Value <> ws2.Cells(iRow, 1).Value And ws1.Cells(iRow, 1).Value <> ws3.Cells(iRow, 1).Value Then
ws1.Cells(iRow, 1).Interior.ColorIndex = 3
ElseIf ws1.Cells(iRow, 1).Value = ws2.Cells(iRow, 1).Value And ws1.Cells(iRow, 1).Value <> ws3.Cells(iRow, 1).Value Then
ws1.Cells(iRow, 1).Interior.ColorIndex = 6
ws2.Cells(iRow, 1).Interior.ColorIndex = 6
ElseIf ws1.Cells(iRow, 1).Value = ws3.Cells(iRow, 1).Value And ws1.Cells(iRow, 1).Value <> ws2.Cells(iRow, 1).Value Then
ws1.Cells(iRow, 1).Interior.ColorIndex = 6
ws3.Cells(iRow, 1).Interior.ColorIndex = 6
End If
If ws3.Cells(iRow, 1).Value <> ws2.Cells(iRow, 1).Value And ws3.Cells(iRow, 1).Value <> ws1.Cells(iRow, 1).Value Then
ws3.Cells(iRow, 1).Interior.ColorIndex = 3
ElseIf ws3.Cells(iRow, 1).Value = ws2.Cells(iRow, 1).Value And ws3.Cells(iRow, 1).Value <> ws1.Cells(iRow, 1).Value Then
ws3.Cells(iRow, 1).Interior.ColorIndex = 6
ws2.Cells(iRow, 1).Interior.ColorIndex = 6
End If
If ws2.Cells(iRow, 1).Value <> ws3.Cells(iRow, 1).Value And ws2.Cells(iRow, 1).Value <> ws1.Cells(iRow, 1).Value Then
ws2.Cells(iRow, 1).Interior.ColorIndex = 3
End If
Next
End Sub

Compare all columns between two sheets based on a unique identifier column and update Sheet1 rows if difference exists

I have a workbook that has 2 worksheets and sub-sheets Named as per Product Line Column:
NEW DATA sheet
Master Table sheet ("DBQ Query Result")
Subsheets (Driling and Workover, Fishing, Liner Systems, Professional Services, Wellbore Cleaning)
They both have same headers, within the column headers there is a uniqueID column.
PART A
I would like to match uniqueID between those 2 sheets and:
When there is a match, compare row cell values for each column and update if there is difference
When there is a uniqueID in NEW DATA sheet that does not exist in Master Table, I would like this whole row associated to this uniqueId to be copied to Master Table sheet
PART B
I would like to have a new button that when pressed, UniqueID from Master Page will be compared with Unique Id column of each subsheet and:
When there is a match, update subsheet row according to UNIQUEID
When there is no match, that means a new UNIQUEID is created and this should be added to its corresponding subsheet as a last row
I would like to accomplish the above using VBA macro please. I have attached a sample of the excel https://dl.dropboxusercontent.com/u/29585269/Sample.xlsx.
Please let me know if you need any additional information.
I came across few codes online and modified them to fit my need.
So, this is how it goes:
You have 3 Main Sheets next to your PL Sheets - Subsheets (Driling and Workover, Fishing, Liner Systems, Professional Services, Wellbore Cleaning):
Original
Updated
Changes
This code will print the changes between Original Sheet and Updated Sheet:
Option Explicit
Sub CompareSheets()
'
' constants
' worksheets & ranges
' original
Const ksWSOriginal = "ORIGINAL"
Const ksOriginal = "OriginalTable"
Const ksOriginalKey = "OriginalKey"
' updated
Const ksWSUpdated = "UPDATED"
Const ksUpdated = "UpdatedTable"
Const ksUpdatedKey = "UpdatedKey"
' changes
Const ksWSChanges = "CHANGES"
Const ksChanges = "ChangesTable"
' labels
Const ksChange = "CHANGE"
Const ksRemove = "REMOVE"
Const ksAdd = "ADD"
'
' declarations
Dim rngO As Range, rngOK As Range, rngU As Range, rngUK As Range, rngC As Range
Dim c As Range
Dim I As Long, J As Long, lChanges As Long, lRow As Long, bEqual As Boolean
'
' start
Set rngO = Worksheets(ksWSOriginal).Range(ksOriginal)
Set rngOK = Worksheets(ksWSOriginal).Range(ksOriginalKey)
Set rngU = Worksheets(ksWSUpdated).Range(ksUpdated)
Set rngUK = Worksheets(ksWSUpdated).Range(ksUpdatedKey)
Set rngC = Worksheets(ksWSChanges).Range(ksChanges)
With rngC
If .Rows.Count > 1 Then
Range(.Rows(2), .Rows(.Rows.Count)).ClearContents
Range(.Rows(2), .Rows(.Rows.Count)).Font.ColorIndex = xlColorIndexAutomatic
Range(.Rows(2), .Rows(.Rows.Count)).Font.Bold = False
End If
End With
'
' process
lChanges = 1
' 1st pass: updates & deletions
With rngOK
For I = 5 To .Rows.Count
Set c = rngUK.Find(.Cells(I, 1).Value, , xlValues, xlWhole)
If c Is Nothing Then
' deletion
lChanges = lChanges + 1
rngC.Cells(lChanges, 1).Value = ksRemove
For J = 1 To rngO.Columns.Count
rngC.Cells(lChanges, J + 1).Value = rngO.Cells(I, J).Value
rngC.Cells(lChanges, J + 1).Font.Color = vbRed
rngC.Cells(lChanges, J + 1).Font.Bold = True
Next J
Else
bEqual = True
lRow = c.Row - rngUK.Row + 1
For J = 1 To rngO.Columns.Count
If rngO.Cells(I, J).Value <> rngU.Cells(lRow, J).Value Then
bEqual = False
Exit For
End If
Next J
If Not bEqual Then
' change
lChanges = lChanges + 1
rngC.Cells(lChanges, 1).Value = ksChange
For J = 1 To rngO.Columns.Count
If rngO.Cells(I, J).Value = rngU.Cells(lRow, J).Value Then
rngC.Cells(lChanges, J + 1).Value = rngO.Cells(I, J).Value
Else
rngC.Cells(lChanges, J + 1).Value = rngU.Cells(I, J).Value
rngC.Cells(lChanges, J + 1).Font.Color = vbMagenta
rngC.Cells(lChanges, J + 1).Font.Bold = True
End If
Next J
End If
End If
Next I
End With
' 2nd pass: additions
With rngUK
For I = 5 To .Rows.Count
Set c = rngOK.Find(.Cells(I, 1).Value, , xlValues, xlWhole)
If c Is Nothing Then
' addition
lChanges = lChanges + 1
rngC.Cells(lChanges, 1).Value = ksAdd
For J = 1 To rngU.Columns.Count
rngC.Cells(lChanges, J + 1).Value = rngU.Cells(I, J).Value
rngC.Cells(lChanges, J + 1).Font.Color = vbBlue
rngC.Cells(lChanges, J + 1).Font.Bold = True
Next J
End If
Next I
End With
'
' end
Worksheets(ksWSChanges).Activate
rngC.Cells(2, 3).Select
Set rngC = Nothing
Set rngUK = Nothing
Set rngU = Nothing
Set rngOK = Nothing
Set rngO = Nothing
Beep
'
End Sub
This Button Code will Apply Updates to rows noted as "Changes" and "Add" (I dont care about Remove)
Sub Update()
Dim sh1 As Worksheet, sh2 As Worksheet
Dim tempName As String
Dim lastRow1 As Long, lastRow2 As Long
Dim s2Row As Long, s1Row As Long
Application.ScreenUpdating = False
Set sh1 = ActiveWorkbook.Worksheets("ORIGINAL")
Set sh2 = ActiveWorkbook.Worksheets("CHANGES")
lastRow1 = sh1.Cells(Rows.Count, "A").End(xlUp).Row 'Get last row for both sheets
lastRow2 = sh2.Cells(Rows.Count, "A").End(xlUp).Row ' searching both
For s2Row = 2 To lastRow2 'Loop through "CHANGES"
If sh2.Cells(s2Row, 1).Value = "CHANGE" Then
tempName = sh2.Cells(s2Row, 2).Value 'extra step for understanding concept
'There is a match, so now
For s1Row = 2 To lastRow1 'Search through the other sheet
If sh1.Cells(s1Row, 1).Value = tempName Then
For I = 2 To 35
sh1.Cells(s1Row, I).Value = sh2.Cells(s2Row, I + 1).Value 'Copy Values
Next I
End If
Next s1Row
End If
Next s2Row
For s2Row = 2 To lastRow2
If sh2.Cells(s2Row, 1).Value = "ADD" Then
sh2.Range("B" & s2Row & ":BB" & s2Row).Copy 'Copy rows
sh1.Rows(lastRow1 + 1).Insert Shift:=xlDown 'Insert rows
sh1.Cells(lastRow1 + 1, 78).Value = "ADD" 'Classify the row as newly added
End If
Next s2Row
Application.ScreenUpdating = True
Sheets("ORIGINAL").Activate
End Sub
And this button will apply updates to PL Cell Values for existing UniqueIDs changes
Sub Update_PL()
Dim ws As Worksheet
Dim lastRng As Range
Application.ScreenUpdating = False 'speed up code
'Added to loop through all UniqueIDs and update accordingly
Dim sh1 As Worksheet, sh2 As Worksheet
Dim tempName As String
Dim lastRow1 As Long, lastRow2 As Long
Dim s2Row As Long, s1Row As Long
'No Longer requires clearing screen, we will match unique ids and update/add as necessary
'ThisWorkbook.Sheets("ORIGINAL").Rows("5:65536").ClearContents 'clear
Set sh1 = ActiveWorkbook.Worksheets("ORIGINAL") 'Define Master Table
Set sh2 = ws 'Selects Active Sheet
For Each ws In ThisWorkbook.Worksheets
Set lastRng = ThisWorkbook.Sheets("ORIGINAL").Range("A65536").End(xlUp).Offset(1, 0)
Select Case ws.Name
Case "ORIGINAL" 'exlude
Case "UPDATED" 'exlude
Case "CHANGES" 'exlude
Case "Report Table" 'exlude
Case "DASHBOARD" 'exlude
'do nothing
Case Else
ws.Activate
lastRow2 = sh1.Cells(Rows.Count, "A").End(xlUp).Row 'Count Master Table Rows to extract Last Row #
With ActiveSheet
lastRow1 = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row 'Count Active Sheet Rows to extract Last Row #
End With
For s2Row = 2 To lastRow2 'Loop through Active WorkSheet
tempName = sh1.Cells(s2Row, 1).Value 'Define UniqueID to loop
tempPL = sh1.Cells(s2Row, 22).Value 'Define PL to loop
For s1Row = 2 To lastRow1 'Match UniqueIDs between Master sheet and Active Sheet
If ActiveSheet.Cells(s1Row, 1).Value = tempName Then 'If Matches TRUE then
For I = 2 To 35 'Loop all Columns and update as necessary
ActiveSheet.Cells(s1Row, I).Value = sh1.Cells(s2Row, I).Value 'Copy Values
Next I
End If
Next s1Row
Next s2Row
'copy data from individual sheets
'Range("A2", Range("AB65536").End(xlUp)).Copy lastRng
End Select
Next
Application.CutCopyMode = False 'clear clipboard
Application.ScreenUpdating = True
Sheets("ORIGINAL").Activate
End Sub
And this last button is used to Add new UniqueIDs to corresponding PL
Sub Add_Rows()
Dim ws As Worksheet
Dim lastRng As Range
Application.ScreenUpdating = False 'speed up code
'Added to loop through all UniqueIDs and update accordingly
Dim sh1 As Worksheet
Dim tempPL As String
Dim lastRow1 As Long, lastRow2 As Long
Dim s2Row As Long, s1Row As Long
Set sh1 = ActiveWorkbook.Worksheets("ORIGINAL") 'Define Master Table
For Each ws In ThisWorkbook.Worksheets
Set lastRng = ThisWorkbook.Sheets("ORIGINAL").Range("A65536").End(xlUp).Offset(1, 0)
Select Case ws.Name
Case "ORIGINAL" 'exlude
Case "UPDATED" 'exlude
Case "CHANGES" 'exlude
Case "Report Table" 'exlude
Case "DASHBOARD" 'exlude
'do nothing
Case Else
ws.Activate
lastRow2 = sh1.Cells(Rows.Count, "A").End(xlUp).Row 'Count Master Table Rows to extract Last Row #
With ActiveSheet
lastRow1 = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row 'Count Active Sheet Rows to extract Last Row #
End With
For s2Row = 5 To lastRow2 'Loop through Active WorkSheet
If sh1.Cells(s2Row, 78).Value = "ADD" Then
tempPL = sh1.Cells(s2Row, 23).Value
If ActiveSheet.Name = tempPL Then
sh1.Range("A" & s2Row & ":AB" & s2Row).Copy 'Copy rows
ActiveSheet.Rows(lastRow1 + 1).Insert Shift:=xlDown 'Insert rows
sh1.Cells(s2Row, 78).Value = "ADDED" 'Validate Row has been added in Master Sheet
End If
End If
Next s2Row
End Select
Next
Application.CutCopyMode = False 'clear clipboard
Application.ScreenUpdating = True 'Resume ScreenUpdating
Sheets("ORIGINAL").Activate 'Display Original Sheet
End Sub
Complicated? Yeah... but solved my issue.
BR! Eddy