Object Oriented Error -- Referencing Other Worksheets? [duplicate] - vba

This question already has answers here:
Excel VBA, getting range from an inactive sheet
(3 answers)
Closed 6 years ago.
I am using VBA to loop through a list of reference numbers ROID and return the correct full name (ROIDA) from a separate page. The page where the full name is located has the reference number in column D and the full name in column A.
Sub Main()
'Set variable types
Dim WorksheetA As Excel.Worksheet
Dim WorksheetB As Excel.Worksheet
Dim ROID As Range, ROIDA As Range
Set WorksheetA = ActiveWorkbook.Sheets("WorksheetA")
Set WorksheetB = ActiveWorkbook.Sheets("Approval Flows")
'Replacing ROID #s with full Name
'Define range of active requesting offices
Set ROID = WorksheetA.Range(Range("A7"), Range("A7").End(xlDown))
'Define range of attention lines and associated ROIDs
Set ROIDA = WorksheetB.Range(Range("D7"), Range("D7").End(xlDown))
'Loop through ROIDs and replace with ATTN line
For Each ID In ROID
Set Match = ROIDA.Find(ID)
If Not Match Is Nothing Then
ID = Match.Offset(0, -3)
End If
Next ID
End Sub
When I try to run the script, I receive an objected oriented error from this line:
Set ROIDA = WorksheetB.Range(Range("D7"), Range("D7").End(xlDown))
Is this because I'm working with multiple sheets? I am trying hard not to use the activate or select functions.

Yes, if A/B are not active when you run the macro. You need to fully qualify all ranges with sheets. Also better to go the end and work up than go Down in case you have nothing after A7.
With WorksheetA
Set ROID = .Range(.Range("A7"), .Range("A7").End(xlDown))
'Or Set ROID = .Range(.Range("A7"), .Range("A" & Rows.count).End(xlup))
End With
'Define range of attention lines and associated ROIDs
With WorksheetB
Set ROIDA = .Range(.Range("D7"), .Range("D7").End(xlDown))
End With

Related

Looping through filter criteria for a column and performing analysis on visible data to copy to new sheet - VBA Macro

Effectively what I am trying to accomplish is to filter a database (all in Sheet 1) by names, which are given in column A, and then perform various data analysis on the now filtered visible data, and then copy that data to a new sheet in a given cell.
For example, filter the data in Sheet 1 by the name 'Smith' in column A and then let's say sum all of the visible data in column B and print that to cell C3 on Sheet 2. The more advanced data analysis I am sure I can tackle on my own, just want to get rolling here and I am definitely new to VBA macro coding. I have created all of these databases using Python.
The last piece of this, would be being able to loop through all of the filter criteria in column A (which I will not know before-hand and may be anywhere from 10-20 names.
Here is the code I am working with (there are likely some syntax errors in here as well):
Option Explicit
Sub Data()
Dim playername As String
Dim team As String
Dim numFilters As Integer
Dim hits As Integer
Dim src As Worksheet
Dim tgt As Worksheet
Dim filterRange As Range
Dim copyRange As Range
Dim lastRow As Long
Dim i As Integer
team = ThisWorkbook.Sheets(1).Name
numFilters = ActiveSheet.AutoFilter.Filters.Count ' I want this to capture the num of filter criteria for column A
For i = 1 To numFilters
playername = Sheets(team).Filter(i) ' This would be the filter criteria for the given iteration
ActiveSheet.Range("$A$1:$AN$5000").AutoFilter field:=1, Criteria1:=playername
' Create new sheet with name of person
Sheets.Add After:=ActiveSheet
ActiveSheet.Select
ActiveSheet.Name = playername
Set tgt = ThisWorkbook.Sheets(i + 1)
' Perform data analysis (e.g. sum column B of filtered data)
src.AutoFilterMode = False
' Find the last row with data in column A
lastRow = src.Range("A" & src.Rows.Count).End(xlUp).Row
' The range that we are auto-filtering (all columns)
Set filterRange = src.Range("A1:AN" & lastRow)
' Set the range to start in row 2 to prevent copying the header
Set copyRange = src.Range("B2:B" & lastRow)
' Copy the sum of column B to our target cell on the sheet corresponding to this iteration
Application.WorksheetFunction.Sum(copyRange.SpecialCells(xlCellTypeVisible)).Copy tgt.Range("A1")
Next i
End Sub
This is currently failing on the Application.WorksheetFunction.Sum line with the error 'Invalid qualifier'. Thanks for any help and please let me know if something needs clarified.

Extract Row Locations to Use as Reference

I populated an excel sheet with the locations of blank cells in my sheet using suggestions from this post. So I have a Column A filled with locations in the following format
$X$1 or $X2:$X$4.
What I am trying to do is use those row numbers from the column explain above to populate a separate column. I want to use the row numbers as a reference in what to populate for the column. So a Column B looking something like
=$B$1 or =$B$2:$B$4 (took 1 and 2-4 and used it as row number for reference call)
Both columns are referencing a different sheet so please excuse any column naming.
I'm not sure if this is going to require VBA or if I can get away with just using a formula, I expect VBA due to desired specifics. I've looked at post like this and this. But neither of these fully encompass what I'm looking for. Especially since I want it to express all the contents in a $B$2:$B$4 case.
My intuition on how to solve this problem tells me, parse the string from Column A for the 1st number then check if it's the end of the string. If it is, feed it to the reference that populates Column B, if not then find the 2nd number and go through a loop that populates the cell (would prefer to keep all the content in one cell in this case) with each value for each reverence.
i.e.
=$B2
=$B3
=$B4
My question is how do I go about this? How do I parse the string? How do I generate the loop that will go through the necessary steps? Such as using the number as a reference to pull information from a different column and feed it neatly into yet another column.
If (for example) you have an address of $X2:$X$4 then
Dim rng As Range
Set rng = yourSheetReference.Range("$X2:$X$4")
If you want to map that to the same rows but column B then
Set rng = rng.Entirerow.Columns(2)
will do that. note: it's not so clear from your question whether you're mapping X>>B or B>>X.
Once you have the range you want you can loop over it:
For Each c in rng.Cells
'do something with cell "c"
next c
Something like this should work for you:
Sub Tester()
Dim shtSrc As Worksheet, c As Range, rng As Range, c2, v, sep
Set shtSrc = ThisWorkbook.Worksheets("Sheet1") '<< source data sheet
Set c = ActiveSheet.Range("A2") '<<range addresses start here
'process addresses until ColA is empty
Do While c.Value <> ""
'translate range to (eg) Column X
Set rng = shtSrc.Range(c.Value).EntireRow.Columns(24)
sep = ""
v = ""
'build the value from the range
For Each c2 In rng.Cells
v = v & sep & c2.Value
sep = vbLf
Next c2
c.Offset(0, 1) = v '<< populate in colB
Loop
End Sub
Try this code:
Sub Test()
Dim fRng As Range ' the cell that has the formula
Set fRng = Worksheets("sheet1").Range("A1")
Dim tWS As Worksheet 'the worksheet that has the values you want to get
Set tWS = Worksheets("sheet2")
Dim r As Range
For Each r In Range(fRng.Formula).Rows
'Debug.Print r.Row ' this is the rows numbers
Debug.Print tWS.Cells(r.Row, "N").Value 'N is the column name
Next
End Sub

VBA: Use one Excel Sheet to Insert to and/or Update another

Sheet 1 holds a full list of the current state of work orders
Sheet 2 holds recent changes to those work orders and any new work orders
Both sheets have the same format with data in columns A to L.
I need to use Sheet 2 to update the full list held in Sheet 1. Work orders have a unique identifier which is held in column A of each sheet.
In general terms:
Process each row of Sheet 2.
If a matching work order already exists in Sheet 1, update it.
If no matching work order exists in Sheet 1, add it as a new row in Sheet 1.
In column A is the work order number.
There may be better ways to do this, and as #Jeeped said, this has probably been asked before (though I couldn't find it). Hopefully the following is what you need. I've included lots of comments to help you understand the code and modify it should you need to.
Sub ProcessDelta()
'Define the worksheets
Dim shtDelta As Worksheet
Dim shtMaster As Worksheet
Set shtDelta = Worksheets("Sheet2")
Set shtMaster = Worksheets("Sheet1")
Dim intDeltaStartRow As Integer
'I assume there is a header row in the Delta sheet, if not, set this to 1
intDeltaStartRow = 2
Dim intMaxEverWorkOrders As Integer
'One of several ways to find the first blank row in the Master
'sheet is to start somewhere beyond the data and move up
'we use this later
intMaxEverWorkOrders = 1000000
Dim cellDeltaWorkOrder As Range
'Work order from Delta to be processed
Set cellDeltaWorkOrder = shtDelta.Cells(intDeltaStartRow, 1)
'For the destination to which we copy
Dim cellMasterWorkOrder As Range
Dim boolNewWorkOrder As Boolean
'Default to assume it's not a new workorder
boolNewWorkOrder = False
'We'll work from top to bottom in the Delta sheet. When the cell is blank we've finished
While cellDeltaWorkOrder.Value <> ""
'We're going to search for the "current" workorder from the Delta in the Master.
'If it's not there, we'll get an error. So we use "On Error" to handle it
On Error GoTo ErrorStep
'If there is no error, after the following line cellMasterWorkOrder will be the cell containing the matching workorder
Set cellMasterWorkOrder = shtMaster.Cells(WorksheetFunction.Match(cellDeltaWorkOrder.Value, shtMaster.Cells(1, 1).EntireColumn, 0), 1) '
'Reset error handling so any other errors are reported normally
On Error GoTo 0
'Check whether there was an error, if there was this was a new Workorder and needs to go at the end, so set the target cell accordingly
If boolNewWorkOrder = True Then
Set cellMasterWorkOrder = shtMaster.Cells(intMaxEverWorkOrders, 1).End(xlUp).Offset(1, 0)
boolNewWorkOrder = False 'reset this so we can check again for the next row to be processed
End If
'Output Row into Master
cellMasterWorkOrder.EntireRow.Value = cellDeltaWorkOrder.EntireRow.Value
'Move to next row in the Delta
Set cellDeltaWorkOrder = cellDeltaWorkOrder.Offset(1, 0)
Wend
'We don't want to run the error step at this point so ..
Exit Sub
ErrorStep:
'It wasn't found, which throws an error, and so it needs added as a new row.
boolNewWorkOrder = True
Resume Next
End Sub

Error Finding multiple date ranges in Excel List

Getting an object variable or with variable not set error. All i'm trying to do is position myself to be able to analyze data from the newStartDate to the newEndDate and compare it to the data in between oldStartDate and oldEndDate. Stuck on the finding the addresses of the dates in the "Master List" Unsure why i'm struggling with this it's a simple task, but I can't seem to solve the error. Any thoughts? I have read the other posts similar to this and can't seem to figure out what i'm doing differently. Thanks in advance Code below:
Note: 1/1/14 is the date set in the range of newStartDate. This date does not exist as business was not conducted until the second. I had found in a post that that the "Set newStartDateFinder" line at the bottom would find the next closest date if the exact date was not found..i'm beginning to think that's not the case since when I attempt to run the debugger it appears to be empty.
Option Explicit
Sub Gather_Calculate_Performance()
'Variable declaration
Dim EBM As Workbook
Dim masterList, controlOut As Worksheet
Dim newStartDate As Range
Dim newEndDate As Range
Dim oldStartDate As Range
Dim oldEndDate As Range
Dim newStartDateFinder As Range
Dim newEndDateFinder As Range
Dim oldStartDateFinder As Range
Dim oldEndDateFinder As Range
'Setting main objects
Set EBM = Workbooks("Monthly Analysis (DEV)")
Set masterList = EBM.Sheets("Master List")
Set controlOut = EBM.Sheets("Control.Output")
'setting main variables
Set newStartDate = controlOut.Range("B" & 5)
Set newEndDate = controlOut.Range("B" & 6)
Set oldStartDate = controlOut.Range("D" & 5)
Set oldEndDate = controlOut.Range("D" & 6)
'Find addresses for dates
Set newStartDateFinder = masterList.Range("A:A").Find(newStartDate, LookIn:=xlValues, LookAt:=xlWhole)
Debug.Print newStartDateFinder.Address
End Sub
Yes, the Find function will look for an exact match, if you set the LookAt argument to xlWhole. (Setting it to xlPart would find matches where the search string exists in part of the cell. So, the Find function won't work in the way you suspected here.
I was thinking you could use a VLOOKUP or MATCH function to find the next closest date to newStartDate but after testing, it didn't work the way I thought it would.
However, this loop while work. If I find a more efficient way, I will update the answer.
'Find addresses for dates
Dim i as Integer
i = 0
Do
Set newStartDateFinder = masterList.Range("A:A").Find(newStartDate.Value +i, LookIn:=xlValues, LookAt:=xlWhole)
i = i + 1
Loop Until Not newStartDateFinder is Nothing
Debug.Print newStartDateFinder.Address

Count number of rows in a different Excel Sheet [duplicate]

This question already has answers here:
Excel VBA, getting range from an inactive sheet
(3 answers)
Closed 7 years ago.
It is in the same workbook. I have a few numbers in a range in Sheet3 and the button is in Sheet2. I want it to count the number of rows and then return the value to me in a msgbox. If I run this with the Sheet3 open it runs fine. If I run it with a different sheet active I get an object error for the counting part. It does insert the 3 in cell A2 no matter what sheet is active.
Sub problem3run()
Dim rngtest As Range
Set rngtest = Sheet3.Range("A2")
rngtest.Value = 3
Dim rngacount As Integer
rngacount = Sheet3.Range(Range("A4"), Range("A4").End(xlDown)).Rows.Count
MsgBox (rngacount)
End Sub
What is messed up in this?
Two issues here. The first is that data type Integer can't hold all the rows in certain excel files, so you'll want to use Long instead. The second is that you are defining rngacount with unqualified range objects. Try this:
Sub problem3run()
Dim rngtest As Range
Set rngtest = Sheet3.Range("A2")
rngtest.Value = 3
Dim rngacount As Long '<~ use Long here rather than Integer
With Sheet3 '<~ use a With here to qualify ranges
rngacount = .Range(.Range("A4"), .Range("A4").End(xlDown)).Rows.Count
End With
MsgBox (rngacount)
End Sub