How to fix Error Runtime 9 when comparing two workbooks - excel

I am trying to create a formula that compares two workbooks.
I get:
Run-time error 9.
Here is the code:
Sub Compare()
Dim wb1 As Workbook
Dim wb2 As Workbook
Set wb1 = Workbooks("Testing1.xlsx")
Set wb2 = Workbooks("Testing2.xlsx")
'Setting variable to represent last row and last column
lRow = Cells(Rows.Count, 1).End(xlUp).Row
lCol = Cells(1, Columns.Count).End(xlToLeft).Column
For i = 2 To lRow
For j = 2 To lCol
'Created the IF then Statement to Highlight Cells that show a difference
If wb2.Sheets("Sheet1").Cells(i, j) <> wb1.Sheets("Sheet1").Cells(i, j) Then
wb2.Sheets("Sheet1").Cells(i, j).Interior.ColorIndex = 5
End If
Next j
Next i
End Sub

Compare the Same Cells in Two Different Workbooks
This is just a basic example that may serve you well at this stage.
Option Explicit
Sub CompareBasic()
' Source: compare; just read
Dim swb As Workbook: Set swb = Workbooks("Testing1.xlsx")
Dim sws As Worksheet: Set sws = swb.Worksheets("Sheet1")
' Destination: compare and highlight
Dim dwb As Workbook: Set dwb = Workbooks("Testing2.xlsx")
Dim dws As Worksheet: Set dws = dwb.Worksheets("Sheet1")
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, "A").End(xlUp).Row
Dim dlCol As Long
dlCol = dws.Cells(1, dws.Columns.Count).End(xlToLeft).Column
Application.ScreenUpdating = False
Dim r As Long
Dim c As Long
For r = 2 To dlRow
For c = 2 To dlCol
If dws.Cells(r, c).Value <> sws.Cells(r, c).Value Then
' Using 'Color' is preferred for it to work the same,
' not depending on which color palette is used.
dws.Cells(r, c).Interior.Color = vbYellow
Else
' It may have previously been different (highlighted)
' but now it's the same (not highlighted):
dws.Cells(r, c).Interior.Color = xlNone
End If
Next c
Next r
Application.ScreenUpdating = True
MsgBox "Differences highlighted.", vbInformation
End Sub

Related

I can't compare the Dates on VBA

I'm trying to compare the dates that I choose. I mean I'm trying to take the some items which has a date earlier. So I wrote this on VBA. But I noticed that when I run this code the output was the same as input. So it tries to find the earlier items but it couldn't compare so all items are copied.
Private Sub Macro1()
a = Worksheets("SVS").Cells(Rows.Count, 1).End(xlUp).Row
For i = 3 To a
If Worksheets("SVS").Cells(i, 22).Value < CDate("28/02/2023") Then
Worksheets("SVS").Rows(i).Copy
Worksheets("Summary").Activate
b = Worksheets("Summary").Cells(Rows.Count, 1).End(xlUp).Row
Worksheets("Summary").Cells(b + 1, 1).Select
ActiveSheet.Paste
Worksheets("SVS").Activate
End If
Next i
Application.CutCopyMode = False
ThisWorkbook.Worksheets("SVS").Cells(1, 1).Select
End Sub
What is missing in the code? I wanna learn.
Check you have a valid date to compare with.
Option Explicit
Private Sub Macro1()
Dim wb As Workbook, ws As Worksheet, v
Dim lastrow As Long, i As Long, b As Long, n As Long
Set wb = ThisWorkbook
Set ws = wb.Worksheets("Summary")
b = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
With wb.Sheets("SVS")
lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
For i = 3 To lastrow
v = .Cells(i, 22) ' col V
If IsDate(v) Then
If CDbl(v) < DateSerial(2023, 2, 28) Then
b = b + 1
.Rows(i).Copy ws.Cells(b, 1)
n = n + 1
End If
End If
Next i
End With
MsgBox n & " rows copied to Summary", vbInformation, lastrow - 2 & " rows checked"
End Sub
Append If Earlier Date
Option Explicit
Sub AppendEarlierDate()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Sheets("SVS")
Dim srg As Range
Set srg = sws.Range("V3", sws.Cells(sws.Rows.Count, "V").End(xlUp))
Dim surg As Range, sCell As Range, sValue
For Each sCell In srg.Cells
sValue = sCell.Value
If IsDate(sValue) Then
If sValue < DateSerial(2023, 2, 28) Then
If surg Is Nothing Then
Set surg = sCell
Else
Set surg = Union(surg, sCell)
End If
End If
End If
Next sCell
If surg Is Nothing Then Exit Sub
Dim dws As Worksheet: Set dws = wb.Sheets("Summary")
If dws.FilterMode Then dws.ShowAllData
Dim dlCell As Range, dfCell As Range
Set dlCell = dws.Cells.Find("*", , xlFormulas, , xlByRows, xlPrevious)
If dlCell Is Nothing Then
Set dfCell = dws.Range("A1")
Else
Set dfCell = dws.Cells(dlCell.Row + 1, "A")
End If
surg.EntireRow.Copy dfCell
End Sub

Find text & insert range 7 rows above & shift down

Hi I have recurring text in a column that says: " "command": 16, "
Every time that text occurs I want to insert a set range from sheet 2, 7 rows above
I have this code but can't get it working.. any ideas
Sub Find_Insert()
Application.ScreenUpdating = False
Dim m As Long
Dim Lastrow2 As Long
Sheets("servo commands").Range("B1:B192").Copy 'sheet with set range to copy
Worksheets("Import").Activate
Lastrow2 = Cells(Rows.Count, "A").End(xlUp).Row
For m = Lastrow2 To 1 Step -1
If Cells(m, "A").Value = " ""command"": 16," Then Cells(m, "A").Offset(-7, 0).Select
Selection.Insert Shift:=xlDown
Next
Application.ScreenUpdating = True
End Sub
many thanks in advance
Insert Range With Offset
Sub InsertCells()
Const DST_ROW_OFFSET As Long = 7
Const DST_CRIT_STRING As String = " ""command"": 16,"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Sheets("Servo Commands")
Dim srg As Range: Set srg = sws.Range("B1:B192")
Dim dws As Worksheet: Set dws = wb.Sheets("Import")
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, "A").End(xlUp).Row
Application.ScreenUpdating = False
Dim dr As Long, dString As String
For dr = dlRow To DST_ROW_OFFSET + 1 Step -1
dString = CStr(dws.Cells(dr, "A").Value)
If StrComp(dString, DST_CRIT_STRING, vbTextCompare) = 0 Then
srg.Copy
dws.Cells(dr, "A").Offset(-DST_ROW_OFFSET).Insert Shift:=xlShiftDown
dr = dr - DST_ROW_OFFSET
End If
Next dr
Application.CutCopyMode = False
Application.ScreenUpdating = True
MsgBox "Cells inserted."
End Sub

Coloring row when condition is met

I am trying to color the cell when condition is met and valid value for package of a product is found in another column in a different sheet.
There is a problem with the if statement.
Sub validation()
Dim lastRow_s As Long
Dim lastRow_m As Long
lastRow_s = Sheets("product").Cells(Rows.Count, "D").End(xlUp).Row
lastRow_m = Sheets("product").Cells(Rows.Count, "H").End(xlUp).Row
For i = 2 To lastRow_s
For j = 2 To lastRow_m
If Sheets("product").Cells(i,"D").Value =
Sheets("valid_package").Cells(j,"A").Value And
Sheets("product").Cells(i, "H").Value =
Sheets("valid_package").Cells(j,"B").Value Then
Sheets("product").Cells(i, "H").Value = vbGreen
End If
Next j
Next i
End Sub
I am trying to iterate over two columns to make sure that the product in column D has a valid package in column H in the product sheet. In the valid_package sheet there is a column for product and package that are valid for this products, so valid_package looks like this:
Product (this is column A from valid package)
Package (this is column B from valid package)
Product A
65x3
Product A
63x3
Product B
65x3
Product B
60x3
Product C
15
Product C
10x3
Product C
15
Product D
10
The product sheet is like this if you take only the two columns:
Product (this is column D from products)
Package (this is column H from products)
Product A
65x3
Product C
63x3
Product B
65x3
Product C
60x3
Product A
15
Product B
10x3
Product C
15
Product E
10
Product C
15
Product D
10
I want to highlight correct package in column H for sheet product or incorrect package in column H for sheet product, it doesn't matter what is colored.
I get
Expected: "line number or label or statement or end of statement.
Color Conditionally Matching Cells
Option Explicit
Sub TestAll()
ValidationQuickFix
ValidationReadable
ValidationEfficient
' Result on 1000 matches in 10000 rows of destination
' with only 10 rows of unique source values:
' Quick Fix: 6,1875
' Readable: 2,21484375
' Efficient: 0,87890625
End Sub
Sub ValidationQuickFix()
Dim t As Double: t = Timer
ThisWorkbook.Activate
Dim lastRow_s As Long
lastRow_s = Worksheets("valid_package").Cells(Rows.Count, "A").End(xlUp).Row
Dim lastRow_d As Long
lastRow_d = Worksheets("product").Cells(Rows.Count, "D").End(xlUp).Row
Dim i As Long, j As Long
For i = 2 To lastRow_d
For j = 2 To lastRow_s
If Worksheets("product").Cells(i, "D").Value = _
Worksheets("valid_package").Cells(j, "A").Value Then
If Worksheets("product").Cells(i, "H").Value = _
Worksheets("valid_package").Cells(j, "B").Value Then
Worksheets("product").Cells(i, "H").Interior.Color = vbGreen
Else
Worksheets("product").Cells(i, "H").Interior.Color = xlNone
End If
End If
Next j
Next i
Debug.Print "Quick Fix: " & Timer - t
End Sub
Sub ValidationReadable()
Dim t As Double: t = Timer
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets("valid_package")
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, "A").End(xlUp).Row
Dim dws As Worksheet: Set dws = wb.Worksheets("product")
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, "D").End(xlUp).Row
Dim i As Long, j As Long
For i = 2 To dlRow
For j = 2 To slRow
If dws.Cells(i, "D").Value = sws.Cells(j, "A").Value Then
If dws.Cells(i, "H").Value = sws.Cells(j, "B").Value Then
dws.Cells(i, "H").Interior.Color = vbGreen
Else
dws.Cells(i, "H").Interior.Color = xlNone
End If
End If
Next j
Next i
Debug.Print "Readable: " & Timer - t
End Sub
Sub ValidationEfficient()
Dim t As Double: t = Timer
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets("valid_package")
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, "A").End(xlUp).Row
Dim srg1 As Range: Set srg1 = sws.Range("A2:A" & slRow)
Dim srg2 As Range: Set srg2 = sws.Range("B2:B" & slRow)
Dim dws As Worksheet: Set dws = wb.Worksheets("product")
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, "D").End(xlUp).Row
Dim drg1 As Range: Set drg1 = dws.Range("D2:D" & dlRow)
Dim drg2 As Range: Set drg2 = dws.Range("H2:H" & dlRow)
Dim ddrg As Range
Dim dCell As Range
Dim sIndex As Variant
Dim dr As Long
For dr = 1 To drg1.Rows.Count
sIndex = Application.Match(drg1.Cells(dr).Value, srg1, 0)
If IsNumeric(sIndex) Then
If drg2.Cells(dr).Value = srg2.Cells(sIndex).Value Then
If ddrg Is Nothing Then
Set ddrg = drg2.Cells(dr)
Else
Set ddrg = Union(ddrg, drg2.Cells(dr))
End If
End If
End If
Next dr
If Not ddrg Is Nothing Then
drg2.Interior.Color = xlNone
ddrg.Interior.Color = vbGreen
End If
Debug.Print "Efficient: " & Timer - t
End Sub
Please, test the next code. It should be fast, using Find, placing the range to be colored in a Union range and coloring it at the code end. I hope that I correctly understood what you want and mostly what you have...
Sub validation()
Dim shP As Worksheet, shVP As Worksheet, rngColor As Range, rngA As Range, rngB As Range
Dim lastRow_P As Long, lastRow_VP As Long, cellMatch As Range, i As Long
Set shP = Sheets("product")
Set shVP = Sheets("valid_package")
lastRow_P = shP.cells(rows.Count, "D").End(xlUp).row
lastRow_VP = shVP.cells(rows.Count, "A").End(xlUp).row
Set rngA = shVP.Range("A2:A" & lastRow_VP)
For i = 2 To lastRow_P
Set cellMatch = rngA.Find(what:=shP.cells(i, "D").Value, LookIn:=xlValues, Lookat:=xlWhole)
If Not cellMatch Is Nothing Then
If cellMatch.Offset(0, 1).Value = shP.cells(i, "H").Value Then
If rngColor Is Nothing Then
Set rngColor = shP.cells(i, "H")
Else
Set rngColor = Union(rngColor, shP.cells(i, "H"))
End If
End If
End If
Next i
If Not rngColor Is Nothing Then rngColor.Interior.color = vbGreen
End Sub

How to Automated extraction of a specific column (2nd) from multiple Sheets(1,2,3...n) to one master sheet using VBA macro. could you help me below,

Private Sub CommandButton1_Click()
'To count sheets in excel file
totalsheets = Worksheets.Count
For i = 1 To totalsheets
If Worksheets(i).Name <> "MasterSheet" Then
'cheking last filled row on each sheet
lastrow = Worksheets(i).Cells(Rows.Count, 1).End(xlUp).Row
For j = 1 To lastrow
Worksheets(i).Activate
Worksheets(i).Cells(j, 2).Select
Selection.Copy
Worksheets("MasterSheet").Activate
lastcln = Worksheets("MasterSheet").Cells(1, Columns.Count).End(xlToLeft)
Worksheets("MasterSheet").Cells(j, lastcln + 1).Select
ActiveSheet.Paste
Next
End If
Next
End Sub
Try this
For i = 1 To totalsheets
If Worksheets(i).Name <> "MasterSheet" Then
' change this according to your need
firstrow = 1
'last row of source
lastrow = Worksheets(i).Cells(Rows.Count, 1).End(xlUp).Row
'last column of destination
lastcln = Worksheets("MasterSheet").Cells(1, Columns.Count).End(xlToLeft)
'more efficient procedure as suggested by Nathan
Worksheets("MasterSheet").Cells(firstrow, lastcln + 1).Value = Worksheets(i).Range(Cells(firstrow, 2), Cells(lastrow, 2)).Value
End If
Next
Copy Column From Multiple Worksheets
Option Explicit
Sub CopyColumn()
' Source
Const sfRow As Long = 1
Const sCol As String = "B"
' Destination
Const dName As String = "MasterSheet"
Const dfRow As Long = 1
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim wsrCount As Long: wsrCount = wb.Worksheets(1).Rows.Count
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dfCell As Range ' Note that the left-most column cannot be column 'A'.
Set dfCell = dws.Cells(dfRow, dws.Columns.Count).End(xlToLeft).Offset(, 1)
' Declare additional variables.
Dim sws As Worksheet ' Source Worksheet
Dim srg As Range ' Source Range
Dim slCell As Range ' Source Last Cell
Dim drg As Range ' Destination Range
' Copy.
For Each sws In wb.Worksheets
If StrComp(sws.Name, dName, vbTextCompare) <> 0 Then
Set slCell = sws.Cells(wsrCount, sCol).End(xlUp)
Set srg = sws.Range(sws.Cells(sfRow, sCol), slCell)
' Either for values only (more efficient)...
Set drg = dfCell.Resize(srg.Rows.Count)
drg.Value = srg.Value
' ... or for values, formats, formulas:
'srg.Copy dfCell ' no need for 'drg'.
' (A third, most flexible option is to use 'PasteSpecial'.)
Set dfCell = dfCell.Offset(, 1) ' next column
End If
Next sws
End Sub

Create new worksheet for each unique value

I have the following code that does a great job at copying relevant data into my sheets. I create each sheet manually for every unique department in column J, then I run this macro. I would like a macro that creates the sheets dynamically based on unique values within column J. I have found good resources online but the ones I've found seem to error when it reaches a row that has already had a sheet created for it. I have included the code I'm currently using as well as a screenshot of my inventory sheet before I manually create the other worksheets
Sub CopyRows()
Dim bottomJ As Integer
bottomJ = Range("J" & Rows.Count).End(xlUp).Row
Dim c As Range
Dim ws As Worksheet
For Each c In Sheets("All Dept.").Range("J2:J" & bottomJ)
For Each ws In Sheets
ws.Activate
If ws.Name = c Then
c.EntireRow.Copy Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
End If
Next ws
Next c
End Sub
Try this.
Sub CreateSheets()
Dim rng As Range
Dim cl As Range
Dim dic As Object
Dim ky As Variant
Set dic = CreateObject("Scripting.Dictionary")
With Sheets("Sheet1")
Set rng = .Range(.Range("J2"), .Range("J" & .Rows.Count).End(xlUp))
End With
For Each cl In rng
If Not dic.exists(cl.Value) Then
dic.Add cl.Value, cl.Value
End If
Next cl
For Each ky In dic.keys
Sheets.Add(After:=Sheets(Sheets.Count)).Name = dic(ky)
Next ky
End Sub
Create Criteria Worksheets
The problem with your idea is e.g. that you use the Hafiz Sb's CreateSheets procedure to create the worksheets and then you use your CopyRows procedure to write the data. Now you add more data to the main worksheet and you're stuck. How will you add the new data to the respective worksheets?
The following assumes that you will only add, not delete data from the main worksheet.
It will copy the main worksheet as many times as there are unique values in a column ('scCol') and by using Autofilter, will delete the undesired data on each of the worksheets (it is my idea, but something similar (if not the same) was suggested by Cyril in the comments).
I did something similar here, which writes the worksheets to separate workbooks.
Option Explicit
Sub CriteriaWorksheetsCreator()
' Accompanying procedures:
' ArrUniqueColumnRange
' DeleteWorksheetsViaArray
Const sName As String = "All Dept."
Const sFirst As String = "A1"
Const sfRow As Long = 1 ' Header Row
Const scCol As Long = 10 ' Criteria Column
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim rg As Range: Set rg = sws.Range(sFirst).CurrentRegion
If rg.Rows.Count = 1 Then Exit Sub ' only one (header) row
If rg.Columns.Count < scCol Then Exit Sub ' too few columns
Dim strg As Range
Set strg = rg.Resize(rg.Rows.Count - sfRow + 1).Offset(sfRow - 1)
Dim sdrg As Range: Set sdrg = strg.Resize(strg.Rows.Count - 1).Offset(1)
Dim scrg As Range: Set scrg = sdrg.Columns(scCol)
Dim wsNames As Variant: wsNames = ArrUniqueColumnRange(scrg)
If IsEmpty(wsNames) Then Exit Sub ' no valid data in 'scrg'
Dim tAddress As String: tAddress = strg.Address
Dim cAddress As String: cAddress = scrg.Address
Application.ScreenUpdating = False
DeleteWorksheetsViaArray wb, wsNames
Dim dws As Worksheet
Dim dtrg As Range
Dim dcrg As Range
Dim drg As Range
Dim n As Long
Dim dName As String
For n = 0 To UBound(wsNames)
sws.Copy After:=wb.Sheets(wb.Sheets.Count)
Set dws = ActiveSheet
dName = wsNames(n)
dws.Name = dName
Set dtrg = dws.Range(tAddress)
dtrg.AutoFilter scCol, "<>" & dName
If Application.Subtotal(103, dtrg.Columns(scCol)) > 1 Then
Set dcrg = dws.Range(cAddress)
Set drg = dcrg.SpecialCells(xlCellTypeVisible).EntireRow
drg.Delete
End If
dws.AutoFilterMode = False
Next n
sws.Activate
'wb.Save
Application.ScreenUpdating = True
MsgBox "Criteria worksheets created.", _
vbInformation, "Criteria Worksheets Creator"
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the unique values from the first column of a range,
' in an array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function ArrUniqueColumnRange( _
ByVal rg As Range) _
As Variant
If rg Is Nothing Then Exit Function
Dim Data As Variant
Dim rCount As Long
With rg.Columns(1)
rCount = .Rows.Count
If rCount = 1 Then
ReDim Data(1 To 1, 1 To 1): Data(1, 1) = .Value
Else
Data = .Value
End If
End With
With CreateObject("Scripting.Dictionary")
.CompareMode = vbTextCompare
Dim Key As Variant
Dim r As Long
For r = 1 To rCount
Key = Data(r, 1)
If Not IsError(Key) Then
If Len(Key) > 0 Then
.Item(Key) = Empty
End If
End If
Next r
If .Count = 0 Then Exit Function ' only error values and/or blanks
ArrUniqueColumnRange = .keys
End With
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Deletes all worksheets whose names are in an array ('wsNames'),
' from a workbook ('wb').
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub DeleteWorksheetsViaArray( _
ByVal wb As Workbook, _
ByVal wsNames As Variant)
On Error GoTo ClearError
If wb Is Nothing Then Exit Sub
Dim LB As Long: LB = LBound(wsNames)
Dim UB As Long: UB = UBound(wsNames)
Dim wsnCount As Long: wsnCount = UB - LB + 1
Dim DeleteSheetNames() As String: ReDim DeleteSheetNames(0 To wsnCount - 1)
Dim dn As Long
Dim ws As Worksheet
Dim sn As Long
Dim wsName As String
For sn = LB To UB
wsName = wsNames(sn)
On Error Resume Next
Set ws = wb.Worksheets(wsName)
On Error GoTo ClearError
If Not ws Is Nothing Then
If ws.Visible = xlSheetVeryHidden Then
ws.Visible = xlSheetVisible
End If
DeleteSheetNames(dn) = wsName
dn = dn + 1
Set ws = Nothing
End If
Next sn
If dn = 0 Then Exit Sub
If dn < wsnCount Then
ReDim Preserve DeleteSheetNames(0 To dn - 1)
End If
Application.DisplayAlerts = False
wb.Worksheets(DeleteSheetNames).Delete
Application.DisplayAlerts = True
ProcExit:
Exit Sub
ClearError:
Debug.Print "Run-time error '" & Err.Number & "': " & Err.Description
Resume ProcExit
End Sub

Resources