Match function in VBA gives compile error - excel

I have a work book with two Worksheets. '2020-2021' Worksheet has some unique numbers in its Column D. Result of Match should come to 'Arrears' Worksheet. C2 cell in 'Arrears' has a number which I want to Match in Column D in 2020-2021. Entered the following code.
Range("C3").Value = WorksheetFunction.Match(Range("c2").value,Range('2020-2021'!d11:d206),0)
Gives Compile Error

Qualify (Use Variables)
If you feel like learning something, study the first two versions.
If not, pick one of the solutions in the third version.
Qualify; what does that even mean?
Related to this case, e.g. Range("C3") is not qualified. We don't know for sure where it refers to (belongs). It is short for ActiveSheet.Range("C3") which means that if we select Sheet1 it will refer to C3 on Sheet1, if we select Sheet2 it will refer to C3 on Sheet2 etc.
But if we use Worksheets("Sheet1").Range("C3") we have qualified the range and which ever worksheet we select, it will always refer to C3 on worksheet Sheet1 (Not 100% true because...).
Similarly to the range case, we are saying that the worksheet in Worksheets("Sheet1").Range("C3") is not qualified. The expression is actually short for ActiveWorkbook.Worksheets("Sheet1").Range("C3").
To qualify it, we can do Workbooks("Test.xlsm").Worksheets("Sheet1").Range("C3"). Now we are saying that the range is fully qualified, as is the worksheet. This might often seem unpractical, so ThisWorkbook 'comes to the rescue'.
If you need to refer to the workbook containing this code, just use ThisWorkbook. You don't care if it is called Test.xlsm or Last Years Official Inventory Report whatever.xlsm... just use ThisWorkbook.
Related to our case, we can then fully qualify our range using:
ThisWorkbook.Worksheets("Arrears").Range("C3")
Application.Match vs WorksheetFunction.Match
Sub qualifyAP()
' Define workbook.
Dim wb As Workbook
Set wb = ThisWorkbook ' The workbook containing this code.
' Define worksheets.
Dim src As Worksheet
Set src = wb.Worksheets("2020-2021")
Dim tgt As Worksheet
Set tgt = wb.Worksheets("Arrears")
' Use the Application version of Match.
Dim Result As Variant ' can hold any datatype incl. error value.
Result = Application.Match(tgt.Range("C2").Value, src.Range("D11:D206"), 0)
If Not IsError(Result) Then
tgt.Range("C3").Value = Result
'MsgBox "Data found and transferred."
Else
MsgBox "Data not found. Nothing done."
End If
End Sub
Sub qualifyWF()
' Define workbook.
Dim wb As Workbook
Set wb = ThisWorkbook ' The workbook containing this code.
' Define worksheets.
Dim src As Worksheet
Set src = wb.Worksheets("2020-2021")
Dim tgt As Worksheet
Set tgt = wb.Worksheets("Arrears")
' Use the WorksheetFunction version of Match.
On Error Resume Next
tgt.Range("C3").Value = WorksheetFunction.Match(tgt.Range("C2").Value, _
src.Range("D11:D206"), _
0)
If Err.Number = 0 Then
'MsgBox "Data found and transferred."
Else
MsgBox "Data not found. Nothing done."
End If
On Error GoTo 0
End Sub
Sub qualifyQF()
Worksheets("Arrears").Range("C3").Value = WorksheetFunction _
.Match(Worksheets("Arrears").Range("C2").Value, _
Worksheets("2020-2021").Range("D11:D206"), _
0)
' or:
With Worksheets("Arrears")
.Range("C3").Value = WorksheetFunction _
.Match(.Range("C2").Value, _
Worksheets("2020-2021").Range("D11:D206"), _
0)
End With
' or even:
With Worksheets("Arrears").Range("C3")
.Value = WorksheetFunction _
.Match(.Offset(-1).Value, _
Worksheets("2020-2021").Range("D11:D206"), _
0)
End With
End Sub

Related

Selecting a worksheet based on a cell value in Excel VBA

I am trying to select a particular page based on cell value U2. I am using the backend Excel names not the display names for the sheets. "Sheet11" is the sheet I am currently trying to connect to. I have tried the following codes, but getting run-time error 9, out of range.
What could I try next?
Thanks
'#1
Dim ws As Worksheet
ws = Range("U2")
Set ws = ActiveSheet
'#2
(Range("U2").Activate
'#3
Sheet11.Activate
Works but no variable
'#4
Sheets(Range("U2").Text).Activate
'#5
Sheets(Range("U2").Value).Activate
'#6
Dim GetString As String
GetString = Range("U2")
GetString.Activate
Is this what you are looking for?
Sheets(ActiveSheet.Range("U2").Value).Select
Reference a Worksheet By Its Code Name
Option Explicit
Sub RefByCodeName()
' Write the code name to a string variable ('wscName').
' Adjust the worksheet!
Dim wscName As String: wscName = CStr(Sheet1.Range("U2").Value)
' Using the 'RefWorksheetByCodeName' function, attempt to reference
' the worksheet ('ws') by its code name.
Dim ws As Worksheet: Set ws = RefWorksheetByCodeName(wscName, ThisWorkbook)
' Validate the worksheet.
If ws Is Nothing Then
MsgBox "No worksheet with the code name '" & wscName & "' found.", _
vbCritical
Exit Sub
End If
' Continue, e.g.:
'MsgBox "Name: " & ws.Name & vbLf & "Code Name: " & ws.CodeName, _
vbInformation
' Make sure the workbook is active.
If Not ThisWorkbook Is ActiveWorkbook Then ThisWorkbook.Activate
' Select the worksheet.
ws.Select
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: In a workbook ('wb'), references a worksheet
' by its code name ('WorksheetCodeName').
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function RefWorksheetByCodeName( _
ByVal WorksheetCodeName As String, _
ByVal wb As Workbook) _
As Worksheet
Dim ws As Worksheet
For Each ws In wb.Worksheets
If StrComp(ws.CodeName, WorksheetCodeName, vbTextCompare) = 0 Then
Set RefWorksheetByCodeName = ws
Exit Function
End If
Next ws
End Function
Sheets have 3 ways of referring to them:
Name (What you see on the tab at the bottom)
Index (A number representing the sheet's position in the workbook, i.e. this will change if you change the position of a sheet)
CodeName (This is what you refer to as the back end excel name)
You can select a sheet using any of these. If I had a workbook with tabs named after months in Jan to Dec order and I haven't changed the code names the code to select November using each would be as follows:
1.Name Worksheets("November").Select
2.Index Worksheets(11).Select
3.CodeName Sheet11.Select
Unlike name and index you can refer to the codename directly as it is an object.
the following code uses the index to loop through the sheet codenames comparing them to the value in U2 when it is the same as U2 it will select the sheet.
Dim lCodeName As String
Dim lWSCount, lCount As Integer
lCodeName = ActiveSheet.Range("U2").Value
lWSCount = ActiveWorkbook.Worksheets.Count
For lCount = 1 To lWSCount
If Worksheets(lCount).CodeName = lCodeName Then
Worksheets(lCount).Select
Else
End If
Next

copy and paste error causing workbook to crash

I'm having an issue with copy and pasting from one spreadsheet to another.
I am using the following code:
Sub LoadnH()
Dim NF As Workbook
Dim shtMain As Worksheet
Set shtMain = Worksheets("Main")
Dim filePath As String
Dim strFileName As Variant
strFileName = Application.GetOpenFilename("All Files (*.*), *.*", , "Select File to Import", , False)
shtMain.Range("filePath").Value = strFileName
If strFileName <> False Then
Set NF = Application.Workbooks.Open(strFileName)
Application.CutCopyMode = False
NF.Sheets("Summary").Copy
Application.DisplayAlerts = False
NF.Close False
Dim nH As Worksheet
Set nH = Worksheets("Hedge Data")
nH.Activate
With nH
.Cells.Clear
.Pictures.Delete
.Range("A1").Select
.PasteSpecial xlPasteValues
End With
End If
End Sub
The code errors out at the following point
.PasteSpecial xlPasteValues
The code show a runtime error '1004':
Method 'PasteSpecial' of object'_Worksheet' failed
how can I fix this so this error? Many times when it hits this error excel will crash and shutdown as well.
To Avoid Select and other similar methods you can assign your value of the destination range with the value from your source range.
You are using the Worksheet.Copy method which copies an entire Worksheet not the data in a Range of the worksheet. This will be creating a new copy of your source worksheet each time you run the code but not copying the data of the worksheet to the clipboard. (NB: below demonstrates using the Before parameter which dictates where the Worksheet will be copied to).
The Range.Copy method will copy the defined range's data to the clipboard (unless you specify the destination parameter).
Rather than using Copy/Paste etc. you can assign the value of the destination range with the value from your source range.
These examples below are all for demonstration of the above points and are tested using 2 new workbooks with default names for the workbooks and worksheets.
E.g 1
Sub WorksheetCopyMethod()
Dim SourceWorksheet As Worksheet
Dim DestinationwWorksheet As Worksheet
Set SourceWorksheet = Workbooks("Book1").Sheets("Sheet1")
Set DestinationWorksheet = Workbooks("Book2").Sheets("Sheet1")
SourceWorksheet.Copy DestinationWorksheet
End Sub
The result of this test creates a copy of Sheet1 from Book1 before Sheet1 on Book2.
E.g 2
Sub RangeCopyMethod()
Dim SourceWorksheet As Worksheet
Dim DestinationwWorksheet As Worksheet
Set SourceWorksheet = Workbooks("Book1").Sheets("Sheet1")
Set DestinationWorksheet = Workbooks("Book2").Sheets("Sheet1")
SourceWorksheet.Range("A1").Copy
DestinationWorksheet.Range("A1").PasteSpecial xlPasteValues
End Sub
This example copies cell A1 from Book1 - Sheet1 and pastes it to cell A1 in Book2 - Sheet1.
E.g 3
Sub AvoidSelectMethod()
Dim SourceWorksheet As Worksheet
Dim DestinationwWorksheet As Worksheet
Set SourceWorksheet = Workbooks("Book1").Sheets("Sheet1")
Set DestinationWorksheet = Workbooks("Book2").Sheets("Sheet1")
DestinationWorksheet.Range("A1").Value = SourceWorksheet.Range("A1").Value
End Sub
This example assigns the Value property of A1 from Book1 - Sheet1 to cell A1 in Book2 - Sheet1. It's the same outcome as E.g 2 but avoids using Select, Copy & Paste etc. This method is much faster and generally less error prone than the 2nd example.
Depending on your environment, the first example may be the easiest and quickest method.

Range.Find Function

Using the Range.Find Method doesn't work for the file name.
The Range DocPresent is always "Nothing"
I am processing multiple Excel Sheets and want to track which ones I already processed. To make sure I don't process the Sheet again when I rerun the Macro
Dim wbname1 As String
wbname1 = ActiveWorkbook.Name
Range("A1").End(xlDown).Offset(1, 0) = wbname1
Dim DocPresent As Range
Set DocPresent = Range("A1:A1000").Find(What:=wbname1)
I am expecting the range to return the correct range if it finds the respective cell.
Note that Range("A1").End(xlDown) might end up below A1000 but your .Find is only looking before A1000.
So either use the whole column Range("A:A").Find… or find the last used cell Range("A1", Cells(Rows.Count, "A").End(xlUp)).Find…
And specify a workbook and worksheet for all your ranges!
Dim wbname1 As String
wbname1 = ActiveWorkbook.Name
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("MySheet")
ws.Range("A1").End(xlDown).Offset(1, 0) = wbname1
Dim DocPresent As Range
Set DocPresent = ws.Range("A1", ws.Cells(ws.Rows.Count, "A").End(xlUp)).Find(What:=wbname1, LookAt:=xlWhole)
Note that ThisWorkbook points to the workbook this code is running in. But ActiveWorkbook points to the workbook that has focus (is on top) at the moment the code is running. ActiveWorkbook can easily change by a user's click but ThisWorkbook is always the same.
Also note that the Range.Find method has a LookAt parameter that should always be specified xlWhole or xlPart. Otherwise VBA uses the one that was used last either by VBA or by user interface. So you never know which one VBA is going to use, therefore always specify it.
According to the comment below you should check if your Find method was successfull before you use DocPresent so you don't run into an error:
If Not DocPresent Is Nothing Then
'do your stuff using DocPresent
Else
MsgBox "'" & wbname1 & "' was not found.", vbCritical
Exit Sub
End If

VBA - Unable to set cell value

I am using the code below in a master workbook to open workbooks listed in the range E12:E24.
Once I have opened these workbooks, I need to count the number of open workbooks (in addition to the master workbook) and assign the number to cell E2 in the Portfolio Results sheet.
The code below works just as I would like except I get an error message on the line Worksheets("Portfolio Results").Range("E2") = nFields
It's unclear to me why this is the case. Thanks for any help.
Sub SkipBlankCells2()
Dim cell As Range, rng As Range, FName As String, nFields As Integer
Set rng = Range("E12:E24")
Application.DefaultFilePath = ActiveWorkbook.Path
nFields = 0
For Each cel In rng
If Len(cel) >= 1 Then
FName = cel.Value
Workbooks.Open Filename:=FName
nFields = nFields + 1
End If
Next cel
Debug.Print nFields
Worksheets("Portfolio Results").Range("E2") = nFields
End Sub
You should (almost always) have Option Explicit as your first line of the code.
Your current code contains an error, where you declared the variable
Dim cell as Range
but then in your For loop you're using an undeclared variable cel which defaults to a Variant data-type.
with Option Explicit enabled, the compiler will warn you about these kind of errors.
As to the actual answer, when switching between objects (be it Worksheet or Workbook) it's always a good programming practice to explicitly declare them.
Easiest way to access them is to store them inside a variable:
Dim wb as Workbook: Set wb = Workbooks("Static name")
Dim ws as Worksheet: Set ws = wb.Sheets("Your sheet name")
'later in the code
If wb.ws.Cells(1, 9) = "banana" Then '...
Not only this makes for a more read-able code for somebody else (because if somebody inherits your project, they can't know which workbook or worksheet intended the author to work with), but it also prevents these unnecessary kind of errors where a different Workbook or Worksheet is selected.
As a final note, if you don't know which Workbook might be open at the moment, but want to reference "this" specific one, then use ThisWorkbook instead

Find Sheet Name with table on it

I am trying to find the sheet name that has a specific table name on it. For example:
Set sheetNM = ActiveWorkbook.Names("ratetable").RefersToRange.Parent.Name
Something like that, but would pull the name of the sheet, so I can activate that sheet in order to pull information from it.
This is not something I recommend but as you are referencing the ActiveWorkbook, you can drop the ActiveWorkbook and retrieve it simply as,
dim pws as worksheet, sws as string
sws = range("ratetable").parent.name
set pws = range("ratetable").parent
debug.print sws & " - " & pws.name
While a structured table (aka ListObject object) is listed in the Formulas ► Name Manager, it does not have all of the properties of a defined name. Unfortunately, everything you can do with a name you cannot always do with a ListObject as a ListObject's parent is the Worksheet object, not the workbook.
You can use error trapping to find the sheet containing a table with a given name:
Function FindTableSheet(TableName As String) As String
Dim ws As Worksheet
Dim LO As ListObject
Dim shName As String
For Each ws In Sheets
On Error Resume Next
Set LO = ws.ListObjects(TableName)
If Err.Number = 0 Then
FindTableSheet = ws.Name
Exit Function
Else
Err.Clear
End If
Next ws
FindTableSheet = "Not Found"
End Function
To test it, I named one of my sheets "Data" and added a table called "ratetable" to that sheet. I didn't, however, create any table called "table tennis". I then ran:
Sub test()
Debug.Print FindTableSheet("ratetable")
Debug.Print FindTableSheet("table tennis")
End Sub
With the output:
Data
Not Found
I know this post is old, but for what it's worth, I think the OP was on the right track (looking for the parent name) with the initial code that you originally posted. Calling the table's parent works for me:
ActiveSheet.ListObjects("TableName").Parent.Name

Resources