I keep getting run-time error 1004, when trying to use Rows.Count. It usually occurs the first time I run the code below, but if I reset and run again it works.
It is failing on this line:
LastRow = Cells(Rows.Count, 4).End(xlUp).Row
Any help with getting this code to run reliably would be greatly appreciated!
The code in its entirety is as follows:
Private Sub ImportAPRData_Click()
'Declare variables for columns in "Projects" spreadsheet in Approved Reliability Projects Workbook (Excel)
Dim orgSheetCol(13) As String
orgSheetCol(0) = "$E$" 'Project Title
orgSheetCol(1) = "$D$" 'Circuit Tag
orgSheetCol(2) = "$F$" 'District
orgSheetCol(3) = "$G$" 'State
orgSheetCol(4) = "$M$" 'Date recieved
orgSheetCol(5) = "$J$" 'Planned Capital Cost
orgSheetCol(6) = "$X$" 'Actual Capital Cost
orgSheetCol(7) = "$U$" 'Capital work completed date
orgSheetCol(8) = "$K$" 'Planned O&M Cost
orgSheetCol(9) = "$Y$" 'Actual O&M Cost
orgSheetCol(10) = "$V$" 'O&M work completed date
orgSheetCol(11) = "$AD$" 'Path to RWP file
orgSheetCol(12) = "I" 'Investment Reason
'Declare variables for cell values attained from APR spreadsheet
Dim orgSheetvalues(13) As Variant
orgSheetvalues(0) = "" 'Project Title
orgSheetvalues(1) = "" 'Circuit Tag
orgSheetvalues(2) = "" 'District
orgSheetvalues(3) = "" 'State
orgSheetvalues(4) = "" 'Date recieved
orgSheetvalues(5) = "" 'Planned Capital Cost
orgSheetvalues(6) = "" 'Actual Capital Cost
orgSheetvalues(7) = "" 'Capital work completed date
orgSheetvalues(8) = "" 'Planned O&M Cost
orgSheetvalues(9) = "" 'Actual O&M Cost
orgSheetvalues(10) = "" 'O&M work completed date
orgSheetvalues(11) = "" 'RWP File Path
orgSheetvalues(12) = "" 'Investment Reason
'Declare & Set Variables for opening & working with Excel Wrokbook / worksheet (Approved Relaibility Projects/Projects)
Dim xls As Excel.Application
Dim wkb As Excel.Workbook
Dim wks As Excel.Worksheet
Set xls = New Excel.Application
'Delcare & set variables for loops, excel row, cell numbers, etc.
Dim rownumber As Integer
rownumber = 3
Dim rowstring As String
Dim cellstring As String
Dim i As Integer
'Declare & set variable to see if RWP already exists in table
Dim tablecheck As Integer
tablecheck = 0
'Declare variable for Capital and O&M Costs / completion dates conditions
Dim Condition1 As Boolean
Dim Condition2 As Boolean
Dim Condition3 As Boolean
Dim Condition4 As Boolean
Dim Condition5 As Boolean
Dim Condition6 As Boolean
Dim Condition7 As Boolean
Dim Condition8 As Boolean
Dim LastRow As Integer
'Open Approved Reliability Projects Workbook & set worksheet to "Projects"
xls.Visible = True
xls.UserControl = True
Set wkb = xls.Workbooks.Open("\\pacificorp.us\dfs\SLCCO\SHR02\PD\POWER\AreaSystemFiles\UT\Park_City_Office\Reliability\RWP_Goal_Tracking\Approved Reliability Projects v5.xlsm", ReadOnly:=True, UpdateLinks:=False)
Set wks = wkb.Worksheets("Projects")
'Find row # for last populated row
LastRow = Cells(Rows.Count, 4).End(xlUp).Row 'For some reason it keeps giving me an error here!!!!
'For each row in APR spreadsheet get info, then make sure all criteria are met, then check to see if it already exists in table, if not insert into table
For rownumber = 3 To LastRow
rowstring = CStr(rownumber)
'Pull information from specified row in APR Spreadsheet
For i = 0 To 12
cellstring = orgSheetCol(i) & rowstring
orgSheetvalues(i) = wks.Range(cellstring).Value
If IsError(orgSheetvalues(i)) Then
orgSheetvalues(i) = wks.Range(cellstring).Text
End If
Next i
'Check to make sure that there are planned costs and completion dates before inserting into rwpT Table
Condition1 = orgSheetvalues(5) <> "" And (orgSheetvalues(7) <> "" And orgSheetvalues(7) <> "#") And orgSheetvalues(11) Like "\\*"
Condition2 = orgSheetvalues(5) = "" And orgSheetvalues(7) = "" And orgSheetvalues(11) Like "\\*"
Condition3 = orgSheetvalues(8) <> "" And orgSheetvalues(10) <> "" And orgSheetvalues(10) <> "N/A"
Condition4 = orgSheetvalues(8) = "" And orgSheetvalues(10) = ""
Condition5 = Condition1 And Condition3
Condition6 = Condition1 And Condition4
Condition7 = Condition1 And Condition3
Condition8 = (Condition5 Or Condition6) Or Condition7
If Condition8 Then
tablecheck = DCount("PlanTitle", "rwpT", "PlanTitle = '" & orgSheetvalues(0) & "'") 'check rwp table to see if plan is already there
'If plan is not there insert into rwpT Table
If tablecheck = 0 Then
CurrentDb.Execute "INSERT INTO rwpT (PlanTitle, Circuit, OpArea, State, InvestmentReason, ApprovalDate, PlanCapitalCost, ActualCapitalCost, CapitalWorkCompDate, PlanOMCost, ActualOMCost, OMWorkCompDate, File) Values ('" & orgSheetvalues(0) & "', '" & orgSheetvalues(1) & "', '" & orgSheetvalues(2) & "', '" & orgSheetvalues(3) & "','" & orgSheetvalues(12) & "', '" & orgSheetvalues(4) & "', '" & orgSheetvalues(5) & "', '" & orgSheetvalues(6) & "', '" & orgSheetvalues(7) & "', '" & orgSheetvalues(8) & "', '" & orgSheetvalues(9) & "', '" & orgSheetvalues(10) & "','" & orgSheetvalues(11) & "')"
End If
End If
Next rownumber
'Close Approved Reliability Projects Workbook & remove all handles to it
wkb.Close False 'Close workbook. False is so that it doesn't save
Set wks = Nothing
Set wkb = Nothing
xls.Quit
Set xls = Nothing
End Sub
Change Dim LastRow As Integer to Dim LastRow As Long and it will be fine, there are too many rows to have as an integer.
In VBA it's actually good practice to always use Long instead of Integer as they are both stored as longs then the integer is converted at runtime, do a search on here for more info on it.
MS Access does not have a default Rows property (or if it does, it isn't what you want to use). You want to use Rows in its Excel sense which, if run within an Excel application would default to Application.ActiveWorkbook.ActiveSheet.Rows.
Because Access doesn't know what Rows means, it uses the property from a default instance of the Excel Application object (which is different to your xls object). The default instance doesn't have a workbook open in it, or a worksheet, so it can't determine what Application.ActiveWorkbook.ActiveSheet.Rows (or Application.ActiveWorkbook.ActiveSheet.Cells) means.
Change the line saying
LastRow = Cells(Rows.Count, 4).End(xlUp).Row
so that you fully qualify your methods/properties, i.e.
LastRow = wks.Cells(wks.Rows.Count, 4).End(xlUp).Row
Related
I am making a tool in excel VBA to bulk create some kind of invoices to each customer. We are making LIVE streams and selling kids clothing, then we write all our orders to excel sheet. Example:
orders list
Then we have to sort all those orders by customer (there are many of them) and create some kind of invoice for each customer. Example: "invoice template"
I use this code to bulk create those and download as pdfs.
Sub Create_PDF_Files()
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Dim dsh As Worksheet
Dim tsh As Worksheet
Dim setting_Sh As Worksheet
Set dsh = ThisWorkbook.Sheets("uzsakymai")
Set tsh = ThisWorkbook.Sheets("lapukas")
Set setting_Sh = ThisWorkbook.Sheets("Settings")
Application.DisplayStatusBar = True
Application.StatusBar = ""
Dim i As Integer
Dim File_Name As String
For i = 2 To dsh.Range("A" & Application.Rows.Count).End(xlUp).Row
Application.StatusBar = i - 1 & "/" & dsh.Range("A" & Application.Rows.Count).End(xlUp).Row - 1
tsh.Range("D1").Value = dsh.Range("C" & i).Value
tsh.Range("A4").Value = dsh.Range("B" & i).Value
tsh.Range("B4").Value = dsh.Range("A" & i).Value & " - " & dsh.Range("E" & i).Value
tsh.Range("P4").Value = dsh.Range("D" & i).Value
File_Name = dsh.Range("A" & i).Value & "(" & dsh.Range("C" & i).Value & "-" & dsh.Range("D" & i).Value & ").pdf"
tsh.ExportAsFixedFormat xlTypePDF, setting_Sh.Range("F4").Value & "\" & File_Name
Next i
Application.StatusBar = ""
MsgBox "Done"
End Sub
But what it does is creating invoice for each item.
EXAMPLE
Any ideas how could I make it work for me as I want it to work?
---EDIT---
After ALeXceL answer, it seems to have some bugs. I changed my code to his code, and I see some progress in creating this program, but what it does, is it shows first item correctly, but all the other items are appearing starting on A24 cell. EXAMPLE
---EDIT---
IT WORKS!!!
Assuming that "uzsakymai" is "orders", the 'data sheet' (dsh) and "lapukas" is the 'template' sheet (tsh), I did these changes, added some counters, in order to the logic flows the right way:
Important: before put this code to run you MUST classify the 'orders' table (dsh, or "uzsakymai") first by Name, then, by Size (as you wish, according to the images posted)
Option Explicit
Sub Create_PDF_Files()
Dim Orders_sh As Worksheet
Dim Template_sh As Worksheet
Dim setting_Sh As Worksheet
Dim oCell As Excel.Range
Dim strKey_TheName As String
Dim lngTemplate_A As Long
Dim lngSumOfItems As Long
Dim dblSumOfValues As Double
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Set Orders_sh = ThisWorkbook.Sheets("uzsakymai")
Set Template_sh = ThisWorkbook.Sheets("lapukas")
Set setting_Sh = ThisWorkbook.Sheets("Settings")
Application.DisplayStatusBar = True
Application.StatusBar = ""
Dim lngI As Long
Dim File_Name As String
'At this point, the Orders_sh worksheet should already have its fields properly sorted/ordered. (Name, then Size)
lngI = 2
Application.StatusBar = lngI - 1 & "/" & Orders_sh.Range("A11").End(xlUp).Row - 1 'a maximum of 10 items can be written here!
Set oCell = Orders_sh.Range("A" & lngI) ' the initial cell
Do
strKey_TheName = UCase(Orders_sh.Range("C" & lngI).Value)
lngSumOfItems = 0
dblSumOfValues = 0
Do
Template_sh.Range("D1").Value = Orders_sh.Range("C" & lngI).Value
lngTemplate_A = IIf(lngSumOfItems = 0, 4, Template_sh.Range("A10").End(xlUp).Offset(1, 0).Row)
Template_sh.Range("A" & lngTemplate_A).Value = Orders_sh.Range("B" & lngI).Value
Template_sh.Range("B" & lngTemplate_A).Value = Orders_sh.Range("A" & lngI).Value & " - " & Orders_sh.Range("E" & lngI).Value
Template_sh.Range("P" & lngTemplate_A).Value = Orders_sh.Range("D" & lngI).Value
lngSumOfItems = lngSumOfItems + 1
dblSumOfValues = dblSumOfValues + Orders_sh.Range("D" & lngI).Value
File_Name = lngSumOfItems & "(" & Orders_sh.Range("C" & lngI).Value & "-" & VBA.Round(dblSumOfValues, 0) & ").pdf"
lngI = lngI + 1
Set oCell = oCell.Offset(1, 0)
Loop Until strKey_TheName <> UCase(oCell.Offset(0, 2).Value)
Template_sh.ExportAsFixedFormat xlTypePDF, setting_Sh.Range("F4").Value & "\" & File_Name
Template_sh.Range("D1").Value = ""
Template_sh.Range("A4:P10").ClearContents
Loop Until Len(oCell.Value) = 0
Application.StatusBar = ""
MsgBox "Done"
End Sub
I want a function that loops through closed workbooks having some parameters given from cells of onother workbook. The aim is to count the number of presence of people in some locations considering a month.
Option Explicit
Public Function ContMonth(colleague As Range, location As Range, month As Range) As Long
Dim nameMonth As String
Dim nameLocation As String
Dim nameColleague As String
Dim rangeLocation As String
Dim stringMonth As String
Dim file As Variant
Dim count As Integer
nameMonth = month
nameLocation = location
nameColleague = colleague
Select Case True
Case nameLocation = "ponte milvio"
rangeLocation = "$A$2:$B$2"
Case Else
rangeLocation = "null"
End Select
Select Case True
Case nameMonth = "January"
stringMonth = "-01-2022"
Case Else
stringMonth = "null"
End Select
file = Dir("C:\Users\sbalo\Desktop\Test\*.xlsx")
While (file <> "")
Do While InStr(file, stringMonth) > 0
count = count + Application.CountIf("C:\Users\sbalo\Desktop\Test\" & "[" & file & "]" & "Sheet1" & "'" & "!" & rangeLocation, nameColleague)
file = Dir()
Loop
Wend
End Function
Sub Test()
Dim counter As Long
Dim name As Range
Dim location As Range
Dim month As Range
Set name = Range("A3")
Set location = Range("B2")
Set month = Range("B1")
counter = ContMonth(name, location, month)
End Sub
this time giving me type mismatching on line:
count = count + Application.CountIf("C:\Users\sbalo\Desktop\Test\" & "[" & file &
"]" & "Sheet1" & "'" & "!" & rangeLocation, nameColleague)
I am using a userform to update existing data on a worksheet. I can
create new records just fine. I created an update userform with a
combobox to search for the names. It pulls the persons data just fine and I am able to change the information. But when I go to click the update button, an error occurs. Before it was adding a totally new line which I did not want to happen so I adjusted my code. I just want to update an existing line of data with the edited information.
I have tried to use the MATCH function in VBA after it was replicating records.
Private Sub Update_record_Click()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Master")
Dim n As Long
Dim empname As String
empname = Application.Match(VBA.CStr(Me.Update_record.Value),
sh.Range("C:C"), 0)
sh.Range("A" & empname).Value = Me.First_Name.Value
sh.Range("B" & empname).Value = Me.Last_Name.Value
sh.Range("D" & empname).Value = Me.MainPX.Value
sh.Range("E" & empname).Value = Me.AltPX.Value
sh.Range("F" & empname).Value = Me.Job_Role.Value
sh.Range("G" & empname).Value = Me.WristBand.Value
sh.Range("H" & empname).Value = Me.Team.Value
sh.Range("I" & empname).Value = Me.Unit.Value
Range("A2:J" & n).Sort key1:=Range("A2:A" & n), order1:=xlAscending,
Header:=xlNo
Me.First_Name.Value = ""
Me.Last_Name.Value = ""
Me.MainPX.Value = ""
Me.AltPX.Value = ""
Me.Job_Role.Value = ""
Me.WristBand.Value = ""
Me.Team.Value = ""
Me.Unit.Value = ""
MsgBox "Record has been updated", vbInformation
End Sub
This is where the application is erroring out...It stops here....on this line
empname = Application.Match(VBA.CStr(Me.Update_record.Value),
sh.Range("C:C"), 0)
So the data never gets updated to the row. Below are two screen shots... one of the worksheet and one of the userform.
There are three ways that I can immediatley think to go about it. I haven't tested the first two so let me know if you face any problem.
WAY ONE
Dim fName As String
Dim lName As String
Dim NameToSearch As String
Dim RecRow As Long
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Master")
fName = FirstNameTextbox.Value '<~~ First Name textBox
lName = LastNameTextbox.Value '<~~ Last Name textBox
NameToSearch = fName & ", " & lName
empname = Application.WorksheetFunction.Match(NameToSearch, sh.Range("C:C"), 0)
WAY TWO
This method uses .Find.
Dim fName As String
Dim lName As String
Dim NameToSearch As String
Dim aCell As Range
Dim ws As Worksheet
Dim RecRow As Long
fName = FirstNameTextbox.Value
lName = LastNameTextbox.Value
NameToSearch = fName & ", " & lName
Set ws = ThisWorkbook.Sheets("Master")
With ws
Set aCell = .Columns(3).Find(What:=NameToSearch, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
RecRow = aCell.Row '<~~ This is the row where the data is
Else
MsgBox SearchString & " not Found"
End If
End With
WAY THREE (I prefer This)
Insert a column in the worksheet in Col A and call it ID. This will have unique serial numbers(row numbers?). When reading the item, read that as well and when writing it back to the cells, use that ID to write back. No need to search for the record using Match or .Find
In this case you will always update the row (ID + 1) assuming, the serial number starts at 1 from row 2.
I have a sheet that looks like this:
I have VBA code that launches an email and takes data from the sheet and puts it in the email body based on an inputbox value that is searched for in the sheet. Values are grabbed from the row based on finding that value. What I am having trouble with now is we have many dupes and I want to pull a name only once, and then getting it to loop, creating a new email when it hits a new approver name, then grabbing all of that approver's customers, and so on.
Example from above sheet:
Email says 'Dear Chris,
Your customers Thomas, Mark, and Jared all need to be reviewed."
So I need code that gets all customers (column C) assigned to one approver (column E), but only grabs one instance of each customer name.
Then, it creates a new separate email when it finds the next approver, in this case John. So the approver name becomes a delimiter.
I am unsure how to do this, or what is even the best approach. Can anyone offer up any ideas? I am learning, but this part is giving me trouble.
Here is the code I have so far:
Sub Test()
Dim aOutlook As Object
Dim aEmail As Object
Dim rngeAddresses As Range, rngeCell As Range, strRecipients As String
Dim strbox As String
Dim stritem As String
Dim x As Long
Dim r As Long
Dim lr, lookRng As Range
Dim findStr As String
Dim foundCell As Variant
Dim foundcell1 As Variant
Dim foundcell2 As Variant
Dim strbody As String
Dim sigstring As String
Dim signature As String
Dim findstr1 As String
Dim foundrng As Range
Dim valuefound As Boolean
Dim strFilename As String
Set aOutlook = CreateObject("Outlook.Application")
Set aEmail = aOutlook.CreateItem(0)
'Input box(es)
findStr = InputBox("Enter approver name to find")
'Greeting based on time of day
Select Case Time
Case 0.25 To 0.5
GreetTime = "Good morning"
Case 0.5 To 0.71
GreetTime = "Good afternoon"
Case Else
GreetTime = "Good evening"
End Select
'Search for input box values and set fields to be pulled
lr = Cells(Rows.Count, "c").End(xlUp).Row
Set lookRng = Range("d1:d" & lr)
valuefound = False
For x = 1 To lr
If Range("c" & x).Value = findStr Then
Set foundCell = Range("B" & x).Offset(0, 4)
Set foundcell1 = Range("e" & x).Offset(0, 1)
Set foundcell2 = Range("B" & x).Offset(0, 5)
valuefound = True
End If
Next x
'Ends the macro if input values to not match the sheet exactly
If Not valuefound Then
MsgBox "Is case-sensitive, Must be exact name", vbExclamation, "No
Match!"
Exit Sub
End If
The way I would approach this is to query your table using SQL to exclude any duplicates (I adapted this example), then iterate over the returned recordset using a dictionary to store your approvers and their customers.
To get the below example to work I've added the Microsoft ActiveX Data Objects 6.1 Library (for the SQL), and the Microsoft Scripting Runtime (for the dictionary), I believe it does what you need:
Sub GetApproversAndCustomers()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
strFile = ThisWorkbook.FullName
strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFile _
& ";Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon
'only retrieve unique combinations of approvers and customers
strSQL = "SELECT DISTINCT [Approver Name],[Customer Name] FROM [Sheet1$B1:E11]"
rs.Open strSQL, cn
Dim approvers As Dictionary
Set approvers = New Dictionary
Do Until rs.EOF
'only add the approver to the collection if they do not already exist
If approvers.Exists(rs.Fields("Approver Name").Value) = False Then
'if they dont exist, add both the approver and customer to the dictionary
approvers.Add rs.Fields("Approver Name").Value, rs.Fields("Customer Name").Value
Else
'if they do exist, find the approver and add the customer to the existing list
approvers.Item(rs.Fields("Approver Name").Value) = approvers.Item(rs.Fields("Approver Name").Value) & ", " & rs.Fields("Customer Name").Value
End If
rs.MoveNext
Loop
'iterate over the dictionary, outputting our values
Dim strKey As Variant
For Each strKey In approvers.Keys()
Debug.Print "Dear " & strKey & ", Your customer(s) " & approvers(strKey) & " all need to be reviewed."
Next
End Sub
Here's a version that doesn't use SQL, I hope it works better than the previous one!
It loops over the table until there are no more rows with data in. It creates a dictionary of approvers and adds the corresponding customer (using the offset method) unless that customer has already been added.
Option Explicit
Public Function GetApproversAndCustomers2(ByVal approversColumn As String, ByVal customerNameColumn As String)
Dim approvers As Object
Set approvers = CreateObject("Scripting.Dictionary")
Dim iterator As Integer
iterator = 2
Do While Len(Sheet1.Range(approversColumn & iterator).Value) > 0
Dim approver As String
approver = Sheet1.Range(approversColumn & iterator).Value
If Not approvers.Exists(approver) Then
If Len(approver) > 0 Then
approvers.Add approver, Sheet1.Range(approversColumn & iterator).Offset(0, -2)
End If
Else
If InStr(1, approvers.Item(approver), Sheet1.Range(approversColumn & iterator).Offset(0, -2).Value) = 0 Then
approvers.Item(approver) = approvers.Item(approver) & ", " & Sheet1.Range(approversColumn & iterator).Offset(0, -2).Value
End If
End If
iterator = iterator + 1
Loop
iterator = 2
Dim key As Variant
For Each key In approvers.Keys
Debug.Print "Dear " & key & ", Your customer(s) " & approvers(key) & " all need to be reviewed."
Next
End Function
Can somebody help me with this code, I am getting a subscript out of range error:
The line after the 'creating the sheets is highlighted in yellow in debugger
'Validation of year
If TextBox_Year.Value = Format(TextBox_Year.Value, "0000") Then
'Creating Process
'Creation of new sheet
Workbooks.Add
ActiveWorkbook.SaveAs FileName:= _
"" & Workbooks("Temperature Charts Sheet Creator").Sheets("MENU").Cells(4, 12).Value & "Data Sheet - " & ComboBox_Month.Value & " " & TextBox_Year.Value & ".xls", FileFormat _
:=xlNormal, Password:="", WriteResPassword:="", ReadOnlyRecommended:= _
False, CreateBackup:=False
'Creating of the sheets
Windows("Data Sheet - " & ComboBox_Month.Value & " " & TextBox_Year.Value & ".xls").Activate
Sheets("Sheet3").Select
Sheets("Sheet3").Name = "31 " & ComboBox_Month.Value
Sheets("Sheet2").Select
Sheets("Sheet2").Name = "30 " & ComboBox_Month.Value
Sheets("Sheet1").Select
Sheets("Sheet1").Name = "29 " & ComboBox_Month.Value
For i = 28 To 1 Step -1
Sheets.Add
ActiveSheet.Name = i & " " & ComboBox_Month.Value
Next
Suggest the following simplification: capture return value from Workbooks.Add instead of subscripting Windows() afterward, as follows:
Set wkb = Workbooks.Add
wkb.SaveAs ...
wkb.Activate ' instead of Windows(expression).Activate
General Philosophy Advice:
Avoid use Excel's built-ins: ActiveWorkbook, ActiveSheet, and Selection: capture return values, and, favor qualified expressions instead.
Use the built-ins only once and only in outermost macros(subs) and capture at macro start, e.g.
Set wkb = ActiveWorkbook
Set wks = ActiveSheet
Set sel = Selection
During and within macros do not rely on these built-in names, instead capture return values, e.g.
Set wkb = Workbooks.Add 'instead of Workbooks.Add without return value capture
wkb.Activate 'instead of Activeworkbook.Activate
Also, try to use qualified expressions, e.g.
wkb.Sheets("Sheet3").Name = "foo" ' instead of Sheets("Sheet3").Name = "foo"
or
Set newWks = wkb.Sheets.Add
newWks.Name = "bar" 'instead of ActiveSheet.Name = "bar"
Use qualified expressions, e.g.
newWks.Name = "bar" 'instead of `xyz.Select` followed by Selection.Name = "bar"
These methods will work better in general, give less confusing results, will be more robust when refactoring (e.g. moving lines of code around within and between methods) and, will work better across versions of Excel. Selection, for example, changes differently during macro execution from one version of Excel to another.
Also please note that you'll likely find that you don't need to .Activate nearly as much when using more qualified expressions. (This can mean the for the user the screen will flicker less.) Thus the whole line Windows(expression).Activate could simply be eliminated instead of even being replaced by wkb.Activate.
(Also note: I think the .Select statements you show are not contributing and can be omitted.)
(I think that Excel's macro recorder is responsible for promoting this more fragile style of programming using ActiveSheet, ActiveWorkbook, Selection, and Select so much; this style leaves a lot of room for improvement.)
Subscript out of Range error occurs when you try to reference an Index for a collection that is invalid.
Most likely, the index in Windows does not actually include .xls. The index for the window should be the same as the name of the workbook displayed in the title bar of Excel.
As a guess, I would try using this:
Windows("Data Sheet - " & ComboBox_Month.Value & " " & TextBox_Year.Value).Activate
Option Explicit
Private Sub CommandButton1_Click()
Dim mode As String
Dim RecordId As Integer
Dim Resultid As Integer
Dim sourcewb As Workbook
Dim targetwb As Workbook
Dim SourceRowCount As Long
Dim TargetRowCount As Long
Dim SrceFile As String
Dim TrgtFile As String
Dim TitleId As Integer
Dim TestPassCount As Integer
Dim TestFailCount As Integer
Dim myWorkbook1 As Workbook
Dim myWorkbook2 As Workbook
TitleId = 4
Resultid = 0
Dim FileName1, FileName2 As String
Dim Difference As Long
'TestPassCount = 0
'TestFailCount = 0
'Retrieve number of records in the TestData SpreadSheet
Dim TestDataRowCount As Integer
TestDataRowCount = Worksheets("TestData").UsedRange.Rows.Count
If (TestDataRowCount <= 2) Then
MsgBox "No records to validate.Please provide test data in Test Data SpreadSheet"
Else
For RecordId = 3 To TestDataRowCount
RefreshResultSheet
'Source File row count
SrceFile = Worksheets("TestData").Range("D" & RecordId).Value
Set sourcewb = Workbooks.Open(SrceFile)
With sourcewb.Worksheets(1)
SourceRowCount = .Cells(.Rows.Count, "A").End(xlUp).row
sourcewb.Close
End With
'Target File row count
TrgtFile = Worksheets("TestData").Range("E" & RecordId).Value
Set targetwb = Workbooks.Open(TrgtFile)
With targetwb.Worksheets(1)
TargetRowCount = .Cells(.Rows.Count, "A").End(xlUp).row
targetwb.Close
End With
' Set Row Count Result Test data value
TitleId = TitleId + 3
Worksheets("Result").Range("A" & TitleId).Value = Worksheets("TestData").Range("A" & RecordId).Value
'Compare Source and Target Row count
Resultid = TitleId + 1
Worksheets("Result").Range("A" & Resultid).Value = "Source and Target record Count"
If (SourceRowCount = TargetRowCount) Then
Worksheets("Result").Range("B" & Resultid).Value = "Passed"
Worksheets("Result").Range("C" & Resultid).Value = "Source Row Count: " & SourceRowCount & " & " & " Target Row Count: " & TargetRowCount
TestPassCount = TestPassCount + 1
Else
Worksheets("Result").Range("B" & Resultid).Value = "Failed"
Worksheets("Result").Range("C" & Resultid).Value = "Source Row Count: " & SourceRowCount & " & " & " Target Row Count: " & TargetRowCount
TestFailCount = TestFailCount + 1
End If
'For comparison of two files
FileName1 = Worksheets("TestData").Range("D" & RecordId).Value
FileName2 = Worksheets("TestData").Range("E" & RecordId).Value
Set myWorkbook1 = Workbooks.Open(FileName1)
Set myWorkbook2 = Workbooks.Open(FileName2)
Difference = Compare2WorkSheets(myWorkbook1.Worksheets("Sheet1"), myWorkbook2.Worksheets("Sheet1"))
myWorkbook1.Close
myWorkbook2.Close
'MsgBox Difference
'Set Result of data validation in result sheet
Resultid = Resultid + 1
Worksheets("Result").Activate
Worksheets("Result").Range("A" & Resultid).Value = "Data validation of source and target File"
If Difference > 0 Then
Worksheets("Result").Range("B" & Resultid).Value = "Failed"
Worksheets("Result").Range("C" & Resultid).Value = Difference & " cells contains different data!"
TestFailCount = TestFailCount + 1
Else
Worksheets("Result").Range("B" & Resultid).Value = "Passed"
Worksheets("Result").Range("C" & Resultid).Value = Difference & " cells contains different data!"
TestPassCount = TestPassCount + 1
End If
Next RecordId
End If
UpdateTestExecData TestPassCount, TestFailCount
End Sub
Sub RefreshResultSheet()
Worksheets("Result").Activate
Worksheets("Result").Range("B1:B4").Select
Selection.ClearContents
Worksheets("Result").Range("D1:D4").Select
Selection.ClearContents
Worksheets("Result").Range("B1").Value = Worksheets("Instructions").Range("D3").Value
Worksheets("Result").Range("B2").Value = Worksheets("Instructions").Range("D4").Value
Worksheets("Result").Range("B3").Value = Worksheets("Instructions").Range("D6").Value
Worksheets("Result").Range("B4").Value = Worksheets("Instructions").Range("D5").Value
End Sub
Sub UpdateTestExecData(TestPassCount As Integer, TestFailCount As Integer)
Worksheets("Result").Range("D1").Value = TestPassCount + TestFailCount
Worksheets("Result").Range("D2").Value = TestPassCount
Worksheets("Result").Range("D3").Value = TestFailCount
Worksheets("Result").Range("D4").Value = ((TestPassCount / (TestPassCount + TestFailCount)))
End Sub