Assigning range of cells results in Type Mismatch (Run-time Error 13) - excel

I am trying to automate the population of a Vlookup formula, looking up values from one worksheet in another. There are two worksheets in the workbook, Suppliers and Products. The product code is looked up from the Products worksheet in the Suppliers worksheet.
This is the code:
Dim lastrow As Long
Sheets("Suppliers").Select
lastrow = ActiveSheet.UsedRange.Rows.Count
Dim SuppliersRnge As Range
Set SuppliersRnge = Range(Cells(2, 2), Cells(lastrow, 3))
' This next try was by declaring the first and last rows and columns in Suppliers sheet as variables and passing values to them (passing values not shown here)
' Set SuppliersRnge = .Range(.Cells(SupplierFirstRow, SupplierFirstColumn), .Cells(SupplierLastRow, SupplierLastColumn))
' This next try was by declaring the range as a static set of cells rather than using lastrow
' Set SuppliersRnge = Range("B2:C23")
' This next try was to pick cell references from currently active worksheet
' Set SuppliersRnge = .Range(.Cells(2, 2), .Cells(lastrow, 3))
' This next try was by fully qualifying the name of the worksheet from which the cell reference is drawn
' Set SuppliersRnge = Worksheets(Suppliers).Range(Cells(2, 2), Cells(lastrow, 3))
' Now switching to product sheet
Sheets("Products").Select
' Selecting cell in which vlookup will be added
Range("A4").Select
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC[1],SuppliersRnge,2,FALSE)"
I am declaring SuppliersRnge as a range and using Set to pass to it the range of cells that need to be looked up.
I have tried to do it in five different ways (you will find four of the ways commented out above) with the same result, which is that the string SuppliersRnge literally gets used in the vlookup, resulting in a >#NAME? value where the result of the Vlookup should be.
When I run ?SuppliersRnge in the Immediate window, I get the Type Mismatch (Run-time Error 13).
If I run a Watch on the SuppliersRnge variable, it starts with a "Nothing" value then changes to a blank.
Any idea on where I might be going wrong? Thanks!

Formulas in VBA
Note the single quotes (around the worksheet name) which are only necessary if the worksheet name contains spaces, but it is good practice to use them always.
Option Explicit
Sub writeVLookupFormula()
Const sName As String = "Suppliers" ' Source
Const dName As String = "Products" ' Destination
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim sLast As Long: sLast = sws.UsedRange.Rows.Count
Dim srg As Range: Set srg = sws.Range(sws.Cells(2, 2), sws.Cells(sLast, 3))
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
' R1C1-style
Dim dFormula As String: dFormula = "=VLOOKUP(RC[1],'" & sName & "'!" _
& srg.Address(, , xlR1C1) & ",2,FALSE)"
dws.Range("A4").FormulaR1C1 = dFormula
' Or:
' ' A1-style
' Dim dFormula As String: dFormula = "=VLOOKUP(B4,'" & sName & "'!" _
' & srg.Address & ",2,FALSE)"
' dws.Range("A4").Formula = dFormula
End Sub

Related

VBA cannot AutoFilter a Range for a certain criteria

I am trying to make a Range object of all entrys and than apply a filter, which searches for a number in there.
I want the Range to hold only the matching entrys afterwards, but I always get the error 1004...
Here the code:
Dim rSearch As Range
Dim rResult As Range
Set rSearch = wbMe.Sheets(iCurSheet).Range("F2:F1000")
rSearch.AutoFilter Field:=iColKey, Criteria1:="=" & wbMe.Sheets(iCurSheet).Cells(iLine, iColKey).Value
The last line throws the exception. I found out that the AutoFilter has to be applied to the first line, so .Range("A1:K1"), but I still don't get why I am not able to Filter on a Range, maybe i get the Object wrong?
Thanks in advance!
Edit:
So I tried some stuff:
Set rSearch = wbMe.Sheets(iCurSheet).Range("A2:K1000")
rSearch.AutoFilter Field:=11, Criteria1:="=" & wbMe.Sheets(iCurSheet).Cells(iLine, iColKey).Value
MsgBox "Count Rows rSearch:" & rSearch.Rows.Count
I expected the MsgBox to say smth less, but I get 999, so it hasn't filtered anything.
My guess that I was filtering the wrong column, but I wanna filter on Col K (I need Col F afterwards to search once more, sry for mixing stuff up).
Now I don't get the AutoFilter exception anymore. But for some reason my rSearch range does not shrink.
How do I shrink my Range?
Count Visible Data Cells (Criteria Cells)
A quick fix could be something like
MsgBox "Count Rows rSearch:" & rSearch.Columns(11).SpecialCells(xlCellTypeVisible).Cells.Count - 1
Note that the headers need to be included in the range for AutoFilter to work correctly.
Using SpecialCells
Sub CountVisibleDataCells()
' Define constants.
Const CriteriaIndex As Long = 11
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the worksheet ('ws').
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1")
' Turn off AutoFilter.
If ws.AutoFilterMode Then ws.AutoFilterMode = False
' Reference the range ('rg').
Dim rg As Range: Set rg = ws.Range("A1:K21")
' Store the criteria value from the cell, converted to a string ('CStr'),
' in a string variable ('Criteria'). AutoFilter 'prefers' this.
Dim Criteria As String: Criteria = CStr(ws.Range("M1").Value)
' Filter the range.
rg.AutoFilter Field:=CriteriaIndex, Criteria1:=Criteria
' Reference the visible cells in the criteria column ('vrg').
Dim vrg As Range
Set vrg = rg.Columns(CriteriaIndex).SpecialCells(xlCellTypeVisible)
' Turn off the worksheet auto filter.
ws.AutoFilterMode = False
' Store the number of visible cells of the criteria column
' in a long variable (subtract 1 to not count the header).
Dim CriteriaCount As Long: CriteriaCount = vrg.Cells.Count - 1
' Inform.
MsgBox "Count of '" & Criteria & "': " & CriteriaCount
End Sub
Using Application Count
Sub CountCriteriaCells()
' Define constants.
Const CriteriaIndex As Long = 11
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the worksheet ('ws').
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1")
' Turn off AutoFilter.
If ws.AutoFilterMode Then ws.AutoFilterMode = False
' Reference the range ('rg').
Dim rg As Range: Set rg = ws.Range("A1:K21")
' Store the criteria value from the cell, converted to a string ('CStr'),
' in a string variable ('Criteria').
Dim Criteria As String: Criteria = CStr(ws.Range("M1").Value)
' You may need to modify this because 'CountIf' works differently.
' Reference the criteria data range ('cdrg') (no headers).
Dim cdrg As Range
With rg.Columns(CriteriaIndex)
Set cdrg = .Resize(.Rows.Count - 1).Offset(1)
End With
' Store the number of cells containing the criteria ('CriteriaCount')
' in a long variable.
Dim CriteriaCount As Long
CriteriaCount = Application.CountIf(cdrg, Criteria)
' Inform.
MsgBox "Count of '" & Criteria & "': " & CriteriaCount
End Sub

Write a dynamic sum formula vba that takes range from another sheet

screenshot of code
I am trying to calculate sum in cell "I13" of sheet2 with inputs based on the dynamic range.
Formula
range("I13").formula= "=sum('sheet1'!A1:A3)"
works but the range can be dynamic. For this I have used lr to identify the last row in the range
lr=cells(rows.count,1).end(xlup).row
Now, I want to modify the above formula such that in place of A3, it takes last cell. i.e. A&lr
Have tried using range("I13").formula= "=sum('sheet1'!A1:A"&lr)", but it results in error
Sub MMM()
Windows("Template.xlsx").activate
sheets("sheet1").select
range("a1").select
lr=cells(rows.count,1).end(xlup).row
sheets("sheet2").select
'this code works. But want dynamic range
'range("I13").formula = "= SUM('sheet1'!A1:A3)"
range("I13").formula = "= sum('sheet1'!A1:A&lr)"
End Sub
you can try to define the variable:
Option Explicit ' It should be used when you define variable
Sub MMM()
Dim lr as Range ' Define variable
Windows("Template.xlsx").activate
sheets("sheet1").select
range("a1").select
lr=cells(rows.count,1).end(xlup).row
sheets("sheet2").select
range("I13").formula = "= sum('sheet1'!A1:A&lr)"
End Sub
You have to join the string for the formula like this:
"=SUM('Sheet1'!A1:A" & lastRow & ")"
Alternatively:
If you set the whole range to be summed then you can use the Address of this range. The External-parameter returns the sheet name as well.
Sub MMM()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsSource As Worksheet: Set wsSource = wb.Worksheets("Sheet1")
Dim wsTarget As Worksheet: Set wsTarget = wb.Worksheets("Sheet2")
Dim rgDataToSum As Range
With wsSource
Set rgDataToSum = .Range("A1", .Cells(.Rows.Count, 1).End(xlUp))
End With
wsTarget.Range("I13").Formula = "=SUM(" & rgDataToSum.Address(True, True, External:=True) & ")"
End Sub

How to bypass code if criteria don't match?

The code works when the criteria exists. I get an error when the criteria doesn't exist.
' Define constants.
Const srcName As String = "wfm_rawdata"
Const srcFirst As String = "D2" ' Location for Group
Const dstName As String = "bond_insurance"
Const dstFirst As String = "A2" ' do not change the 'A' (entire row).
'This function will transfer rows from one worksheet to another worksheet
' if the value = specified critiera
' Define workbook.
Dim wb As Workbook: Set wb = ActiveWorkbook ' Workbook containing this code.
' Define Source Range
Dim LastRow As Long
Dim srg As Range
' Define worksheet and column am working on and
' getting the range of last used cell using(LastRow)
With wb.Worksheets(srcName).Range(srcFirst)
LastRow = .Offset(.Worksheet.Rows.Count - .Row).End(xlUp).Row
Set srg = .Resize(LastRow - .Row + 1, 10)
End With
'Combine' critical cells into a range.
Dim brg As Range ' Built Range --> Range in the new sheet
Dim cel As Range ' Current Cell Range --> Range in the current sheet(rawdata)
'for every cell in group within wfm_rawdata sheet if the value = GO
For Each cel In srg.Cells
If cel.Value = "BOND INSURANCE" Then
' If the range in the new sheet have nothing then
' add specific criteria from the group in wfm_rawdata
If brg Is Nothing Then
Set brg = cel
' if there is range in there combine the new and
' old range together using -> Union function
Else
Set brg = Union(brg, cel)
End If
End If
Next cel
Application.ScreenUpdating = False
' Copy and delete critical rows of Source Range.
With wb.Worksheets(dstName).Range(dstFirst)
.Resize(.Worksheet.Rows.Count - .Row + 1, _
.Worksheet.Columns.Count).clear
Set brg = brg.EntireRow ' 'Convert' cells into rows.
brg.Copy .Offset ' Copy. 'Offset' because range is in 'With'.
brg.Delete ' Delete.
End With
How can I use a Boolean or other function to bypass the above code if the criteria doesn't exist?
For example if criteria "dog" exists then run the code and if it doesn't exist bypass the code.
I use this code to run three modules with code similar to the top code.
Sub master()
Call report1
Call report2
Call report3
End Sub
One you've assigned srg you can use Match() to check whether it contains any instances of the term you're interested in:
'...
'...
' Define worksheet and column am working on and getting the range of last used cell using(LastRow)
With wb.Worksheets(srcName).Range(srcFirst)
LastRow = .Offset(.Worksheet.Rows.Count - .Row).End(xlUp).Row
Set srg = .Resize(LastRow - .Row + 1, 10)
End With
'Exit if "BOND INSURANCE" is not found in `srg`
If IsError(Application.Match("BOND INSURANCE", srg, 0)) Then Exit Sub
'...
'...

Creating an IFERROR using INDEX/MATCH formula in VBA Code

I have a VBA tool I'm trying to update by inputting an IFERROR formula into column B on Sheet2 using INDEX/MATCH to pull the data from column F in Sheet 1. The matching criteria is looking at column D in the active row of Sheet 2 and matching it to Column J in Sheet 1.
The resulting formula should look like this
=IFERROR(INDEX(Sheet1!$F:$F,MATCH('Sheet2'!$D2,Sheet1!$J:$J,0)),"")
This is the code I wrote but I'm getting the "Unable to set formulaaray property of the range class" error.
Range("B2").FormulaArray = "=IFERROR(INDEX(Sheet1,C6,MATCH(RC2,Sheet1,RC10,0)),"""")"
I'm still rather new to VBA and in my research I haven't found anything to help. Appreciate any help anyone can give me in solving this error.
I'm trying to adapt/change the current formula coded in the tool to the above. This code was working it's just the user has made some changes to the file and now wants to grab the data as described in my original post.
Range("B2").FormulaArray = "=IFERROR(INDEX(C6,MATCH(RC1&R1C2,C1&C5,0)),"""")": Range("B2:B" & LastRow).FillDown
Range("B:b").EntireColumn.Select
Selection.Copy
Selection.PasteSpecial xlPasteValues
A VBA Lookup (INDEX/MATCH formula)
Adjust the values in the constants section.
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the results of an 'INDEX/MATCH' formula as values.
' Formula: '=IFERROR(INDEX(Sheet1!$F:$F,MATCH(D2,Sheet1!$J:$J,0)),"")'
' Remarks: 'VLOOKUP' doesn't work because 'F' is to the left of 'J':
' wrong '=VLOOKUP(D2,Sheet1!$J:$F,-5,0)' wrong.
' Calls: 'RefColumn'.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub VBALookupFormula()
' Source
Const sName As String = "Sheet1"
Const slCol As String = "J" ' 2. lookup (compare (match))
Const svCol As String = "F" ' 3. value (return)
Const sfRow As Long = 2
' Destination
Const dName As String = "Sheet2"
Const dlCol As String = "D" ' 1. lookup (read)
Const dvCol As String = "B" ' 4. value (write)
Const dfRow As Long = 2
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim slrg As Range: Set slrg = RefColumn(sws.Cells(sfRow, slCol))
If slrg Is Nothing Then Exit Sub ' no data
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dlrg As Range: Set dlrg = RefColumn(dws.Cells(dfRow, dlCol))
If dlrg Is Nothing Then Exit Sub ' no data
Dim slAddress As String: slAddress = slrg.Address
Dim svAddress As String: svAddress = slrg.EntireRow.Columns(svCol).Address
Dim dlAddress As String: dlAddress = dlrg.Cells(1).Address(0, 0)
Dim dvrg As Range: Set dvrg = dlrg.EntireRow.Columns(dvCol)
Dim dFormula As String
' Note the 4 single quotes (necessary when a worksheet name contains spaces)
' and the 4 consecutive double quotes (basically one double quote
' in the formula is two double quotes in VBA).
dFormula = "=IFERROR(INDEX('" _
& sName & "'!" & svAddress & ",MATCH(" & dlAddress & ",'" _
& sName & "'!" & slAddress & ",0)),"""")"
dvrg.Formula = dFormula
dvrg.Value = dvrg.Value
MsgBox "The lookup finished successfully.", vbInformation
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Creates a reference to the one-column range from the first cell
' of a range ('FirstCell') to the bottom-most non-empty cell
' of the first cell's worksheet column.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function RefColumn( _
ByVal FirstCell As Range) _
As Range
If FirstCell Is Nothing Then Exit Function
With FirstCell.Cells(1)
Dim lCell As Range
Set lCell = .Resize(.Worksheet.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
If lCell Is Nothing Then Exit Function
Set RefColumn = .Resize(lCell.Row - .Row + 1)
End With
End Function

Copy and Paste the Unique Values from Filtered Column

I'm trying to get the Unique values from the Filtered Range and trying to paste the same into specific worksheet. But I'm facing a Run-Time Error 1004 (Database or Table Range is not Valid).
Set DataSet = MainSht.Range(Cells(1, 1), Cells(Lrows, Lcols))
With DataSet
.AutoFilter field:=3, Criteria1:=Array("Corporate Treasury - US", "F&A"), Operator:=xlFilterValues
Set DataRng = .Offset(1, 10).Resize(.Rows.Count - 1, 1).SpecialCells(xlCellTypeVisible)
.AutoFilter
With DataRng
.AdvancedFilter Action:=xlFilterCopy, copytorange:=Wb.Sheets("Corporate Treasury - US").Range("A2"), Unique:=True 'Getting Error Here
End With
End With
Appreciate your help in advance!!
Copy Filtered Unique Data
Basically
'Remove' previous filters.
Create accurate range references before applying AutoFilter.
The filter is applied on the Table Range (headers included).
Use error handling with SpecialCells (think no cells found).
Apply SpecialCells to the Data Range (no headers).
It is usually safe to 'remove' the filter after the reference to the SpecialCells range is created.
Copy/paste and only then apply RemoveDuplicates (xlNo when Data Range).
Optionally, apply Sort (xlNo when Data Range) to the not necessarily exact destination range (ducdrg i.e. no empty cells (due to RemoveDuplicates)).
(xlYes when Table Range.)
A Study
Adjust the values in the constants section (the worksheets are off).
Option Explicit
Sub CopyFilteredUniqueData()
' Source
Const sName As String = "Sheet1"
' Copy
Const sCol As Variant = "K" ' or 11
' Filter
Const sfField As Long = 3
Dim sfCriteria1 As Variant
sfCriteria1 = Array("Corporate Treasury - US", "F&A")
Dim sfOperator As XlAutoFilterOperator: sfOperator = xlFilterValues
' Destination
Const dName As String = "Sheet2"
' Paste
Const dFirst As String = "A2"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Debug.Print vbLf & "Source (""" & sws.Name & """)"
' Remove possble previous filters.
If sws.AutoFilterMode Then
sws.AutoFilterMode = False
End If
' Source Table Range
Dim strg As Range: Set strg = sws.Range("A1").CurrentRegion
Debug.Print strg.Address(0, 0)
' Source Column Data Range (No Headers)
Dim scdrg As Range
With strg.Columns(sCol)
Set scdrg = .Resize(.Rows.Count - 1).Offset(1)
End With
Debug.Print scdrg.Address(0, 0) & " (No Headers)"
' Filter.
strg.AutoFilter sfField, sfCriteria1, sfOperator
' Source Filtered Column Data Range (No Headers)
On Error Resume Next
Dim sfcdrg As Range: Set sfcdrg = scdrg.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
sws.AutoFilterMode = False ' no need for the filter anymore
If sfcdrg Is Nothing Then Exit Sub ' no matching cells
Debug.Print sfcdrg.Address(0, 0) & " (No Headers)"
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Debug.Print vbLf & "Destination (""" & dws.Name & """)"
' Destination First Cell
Dim dfCell As Range: Set dfCell = dws.Range(dFirst)
' Destination Column Data Range (No Headers)
Dim dcdrg As Range: Set dcdrg = dfCell.Resize(sfcdrg.Cells.Count)
Debug.Print dcdrg.Address(0, 0) & " (No Headers)"
' Copy.
sfcdrg.Copy dcdrg
' Remove duplicates.
dcdrg.RemoveDuplicates 1, xlNo
Debug.Print dcdrg.Address(0, 0) & " (No Headers, Empty Cells Included)"
' Destination Last Cell
Dim dlCell As Range
Set dlCell = dcdrg.Find("*", , xlFormulas, , , xlPrevious)
' Destination Unique Column Data Range (No Headers)
Dim ducdrg As Range
With dcdrg
Set ducdrg = .Resize(dlCell.Row - .Row + 1)
End With
Debug.Print ducdrg.Address(0, 0) & " (No Headers, Empty Cells Excluded)"
' Sort ascending.
ducdrg.Sort ducdrg, , Header:=xlNo
End Sub
I believe the error is because it cannot past a range of non-contiguous cells within a column.
I got round this by simply using the .copy command, but this will paste your unique list with the underlying formatting. See my solution below -
> Set DataSet = MainSht.Range(Cells(1, 1), Cells(Lrows, Lcols))
>
> With DataSet
> .AutoFilter field:=3, Criteria1:=Array("Corporate Treasury - US", "F&A"), Operator:=xlFilterValues
> Set DataRng = .Offset(1, 10).Resize(.Rows.Count - 1, 1).SpecialCells(xlCellTypeVisible)
> DataRng.Copy Destination:=Wb.Sheets("Corporate Treasury - US").Range("A2:A" & (DataRng.Rows.Count + 2))
>
> End With
If you do not want to bring across cell properties/formatting from the original worksheet, you could combine the .copy command with a .pastespecial to only paste in values, formulas or whatever details you need.

Resources