Guillaume
Guillaume

Reputation: 1

Type mismatch error when converting Excel function with named ranges to VBA

I am trying to replicate a simple excel function into VBA but I get Type mismatch error. Basically, I have two named ranges rDate and rYear and the following Excel function that works perfectly giving the following output:

=IF(YEAR(rDate)=rYear,rYear,"")

https://www.screencast.com/t/rPpsVjudqrI

However, as I mentionned, I get a Type mismatch error when trying to convert it to VBA. Here is my code:

Public ws As Worksheet
Sub Test()
Dim rDate, rYear, rResult, cell As Range

Set ws = Worksheets("Sheet1")
Set rDate = ws.Range("rDate")
Set rYear = ws.Range("rYear")
Set rResult = ws.Range("rResult")

For Each cell In rResult
    If Year(rDate) = rYear Then 'Problematic line
        cell = rYear
    Else
        cell = ""
    End If
Next
End Sub

Please let me know what I am doing wrong. Thank you

Upvotes: 0

Views: 188

Answers (1)

Scott Craner
Scott Craner

Reputation: 152475

vba reacts differently to ranges than the worksheet. In vba one needs to compare the value of one cell to one value not a multi-cell range to a multi-cell range.

instead of trying to equate the whole range pick the one cell in each range based on where cell is located.

To get the correct reference on the vertical range we want to find the relative row:

rDate.Cells(cell.Row - rResult.Row + 1, 1)

and the relative column:

rYear.Cells(1, cell.Column - rResult.Column + 1)

Then:

Dim rDate, rYear, rResult, cell As Range

only will declare cell as a range and the others as Variant.

So use:

Dim rDate As Range, rYear As Range, rResult As Range, cell As Range

The worksheet function is making assumptions on row and column based on the relative location of the formula, that vba does not.

Public ws As Worksheet
Sub Test()
Dim rDate As Range, rYear As Range, rResult As Range, cell As Range

Set ws = Worksheets("Sheet1")
Set rDate = ws.Range("rDate")
Set rYear = ws.Range("rYear")
Set rResult = ws.Range("rResult")

For Each cell In rResult
    If Year(rDate.Cells(cell.Row - rResult.Row + 1, 1)) = rYear.Cells(1, cell.Column - rResult.Column + 1) Then 'Problematic line
        cell = rYear.Cells(1, cell.Column - rResult.Column + 1)
    Else
        cell = ""
    End If
Next
End Sub

A quicker method would be to load the data into memory arrays and loop through those.

Public ws As Worksheet
Sub Test()
Dim rDate, rYear, rResult
Dim i As Long, j As Long

Set ws = Worksheets("Sheet1")
rDate = ws.Range("rDate").Value
rYear = ws.Range("rYear").Value
ReDim rResult(1 To UBound(rDate, 1), 1 To UBound(rYear, 2))

For i = LBound(rDate, 1) To UBound(rDate, 1)
    For j = LBound(rYear, 2) To UBound(rYear, 2)
        If rYear(1, j) = Year(rDate(i, 1)) Then
            rResult(i, j) = rYear(1, j)
            Exit For
        End If
    Next j
Next i
ws.Range("rResult").Value = rResult

End Sub

Every time one accesses the worksheet from vba it slows down the code. With this method we only access the worksheet 3 times, regardless of how large the ranges are.

Upvotes: 1

Related Questions