4

In VBA, why does the following fail?

Dim rng as Range rng = Range("Sheet1:Sheet3!A1")

It throws an HRESULT exception. Is there another way to construct this range in VBA? Note that you can enter a worksheet function like =SUM(Sheet1:Sheet3!A1) and it works fine.

4 Answers 4

4

A Range object is limited to only one worksheet. After all, it can have only a single parent.

The =SUM() function can operate on a group of ranges. (this is true for many worksheet functions)

EDIT#1

I have been searching for a solution since Janauary:

UDF Syntax

.

I have been using an array of ranges. Not a very good solution.

Sign up to request clarification or add additional context in comments.

2 Comments

Simple question, simple answer for the first part. I would still like to know if there's a way to construct the Range object in VBA given an input string that references a 3D range like "Sheet1:Sheet3!A1" or "'Foo 1:Bar'!A3:C4", for example.
@AndreTerra Consider posting a new answer...........I am still interested in making a UDF() work like SUM().
2

Just developing Gary's answer (if you're going to accept an answer, accept his :):

Using Range variable:

Sub SumTest1()

    Dim rSheet1     As Range
    Dim rSheet2     As Range
    Dim rSheet3     As Range
    Dim dSum        As Double

    With ThisWorkbook
        Set rSheet1 = .Sheets("Sheet1").Range("A1")
        Set rSheet2 = .Sheets("Sheet2").Range("A1")
        Set rSheet3 = .Sheets("Sheet3").Range("A1")
    End With

    dSum = WorksheetFunction.Sum(rSheet1, rSheet2, rSheet3)
    Debug.Print CStr(dSum)

End Sub

Using Variant variable:

Sub SumTest2()

    Dim vArray      As Variant
    Dim dSum        As Double

    With ThisWorkbook
        vArray = Array(.Sheets("Sheet1").Range("A1"), .Sheets("Sheet2").Range("A1"), .Sheets("Sheet3").Range("A1"))
    End With

    dSum = WorksheetFunction.Sum(vArray)
    Debug.Print CStr(dSum)

End Sub

Using no variable:

Sub SumTest3()

    Dim dSum        As Double

    With ThisWorkbook
        dSum = WorksheetFunction.Sum(Array(.Sheets("Sheet1").Range("A1"), .Sheets("Sheet2").Range("A1"), .Sheets("Sheet3").Range("A1")))
    End With

    Debug.Print CStr(dSum)

End Sub

1 Comment

I am interested in returning the Range object from a string that describes the range as shown in my question, not so much the sum of the range. However, if I was trying to get the sum, it is best to use Application.Evaluate("SUM(Sheet1:Sheet3!A1)").
1

Here's a set of UDF functions that accomplish essentially the same thing. The only caveat is that the reference to the 3D range is a string i.e. "Jan:Dec!A1" as opposed to straight up Jan:Dec!A1

'Adapted from https://web-beta.archive.org/web/20060313132405/http://www.j-walk.com/ss/excel/eee/eee003.txt by Andre Terra
Function CountIf3D(Range3D As String, Criteria As String, _
    Optional Count_Range As Variant) As Variant

    Dim sTestRange As String
    Dim sCountRange As String
    Dim Sheet1 As Integer
    Dim Sheet2 As Integer
    Dim n As Integer
    Dim Count As Double

    Application.Volatile

    If Parse3DRange(Application.Caller.Parent.Parent.Name, _
      Range3D, Sheet1, Sheet2, sTestRange) = False Then
      CountIf3D = CVErr(xlErrRef)
    End If

    If IsMissing(Count_Range) Then
      sCountRange = sTestRange
    Else
      sCountRange = Count_Range.Address
    End If

    Count = 0
    For n = Sheet1 To Sheet2
      With Worksheets(n)
        Count = Count + Application.WorksheetFunction.CountIf(.Range _
    (sTestRange), Criteria)
      End With
    Next n
    CountIf3D = Count
End Function  'CountIf3D

Function SumIf3D(Range3D As String, Criteria As String, _
    Optional Sum_Range As Variant) As Variant

    Dim sTestRange As String
    Dim sSumRange As String
    Dim Sheet1 As Integer
    Dim Sheet2 As Integer
    Dim n As Integer
    Dim Sum As Double

    Application.Volatile

    If Parse3DRange(Application.Caller.Parent.Parent.Name, _
      Range3D, Sheet1, Sheet2, sTestRange) = False Then
      SumIf3D = CVErr(xlErrRef)
    End If

    If IsMissing(Sum_Range) Then
      sSumRange = sTestRange
    Else
      sSumRange = Sum_Range.Address
    End If

    Sum = 0
    For n = Sheet1 To Sheet2
      With Worksheets(n)
        Sum = Sum + Application.WorksheetFunction.SumIf(.Range _
    (sTestRange), Criteria, .Range(sSumRange))
      End With
    Next n
    SumIf3D = Sum
End Function  'SumIf3D

Function AverageIf3D(Range3D As String, Criteria As String, _
    Optional Average_Range As Variant) As Variant

    Dim sTestRange As String
    Dim sSumRange As String
    Dim Sheet1 As Integer
    Dim Sheet2 As Integer
    Dim n As Integer
    Dim Sum As Double
    Dim Count As Double

    Application.Volatile

    If Parse3DRange(Application.Caller.Parent.Parent.Name, _
      Range3D, Sheet1, Sheet2, sTestRange) = False Then
      AverageIf3D = CVErr(xlErrRef)
    End If

    If IsMissing(Average_Range) Then
      sSumRange = sTestRange
    Else
      sSumRange = Average_Range.Address
    End If

    Sum = 0
    Count = 0
    For n = Sheet1 To Sheet2
      With Worksheets(n)
        Sum = Sum + Application.WorksheetFunction.SumIf(.Range(sTestRange), Criteria, .Range(sSumRange))
        Count = Count + Application.WorksheetFunction.CountIf(.Range(sTestRange), Criteria)
      End With
    Next n
    AverageIf3D = Sum / Count
End Function  'SumIf3D

Function Parse3DRange(sBook As String, SheetsAndRange _
    As String, FirstSheet As Integer, LastSheet As Integer, _
    sRange As String) As Boolean

    Dim sTemp As String
    Dim i As Integer
    Dim Sheet1 As String
    Dim Sheet2 As String

    Parse3DRange = False
    On Error GoTo Parse3DRangeError

    sTemp = SheetsAndRange
    i = InStr(sTemp, "!")
    If i = 0 Then Exit Function

    'next line will generate an error if range is invalid
    'if it's OK, it will be converted to absolute form
    sRange = Range(Mid$(sTemp, i + 1)).Address

    sTemp = Left$(sTemp, i - 1)
    i = InStr(sTemp, ":")
    Sheet2 = Trim(Mid$(sTemp, i + 1))
    If i > 0 Then
      Sheet1 = Trim(Left$(sTemp, i - 1))
    Else
      Sheet1 = Sheet2
    End If

    'next lines will generate errors if sheet names are invalid
    With Workbooks(sBook)
    FirstSheet = .Worksheets(Sheet1).Index
    LastSheet = .Worksheets(Sheet2).Index

    'swap if out of order
    If FirstSheet > LastSheet Then
      i = FirstSheet
      FirstSheet = LastSheet
      LastSheet = i
    End If

    i = .Worksheets.Count
    If FirstSheet >= 1 And LastSheet <= i Then
      Parse3DRange = True
    End If
    End With
Parse3DRangeError:
    On Error GoTo 0
    Exit Function

End Function  'Parse3DRange

2 Comments

Really Cool!!!............Thanks for taking the time to respond........if I could up-vote more than once, I would.
@Gary'sStudent it's a pleasure to help! to be fair most of the code already existed. let me know if you have any further questions on this
-2

Untested, but try this

Dim rng as string
rng = "Sheet1:Sheet3!A1"
worksheet("Sheet1").range("B1").formula = "=SUM(" & rng & ")"

2 Comments

This should work -- or at least it will evaluate -- depending on OP's needs (in-fact the OP has already indicated awareness of this). But as Gary notes, you absolutely cannot define a Range object that spans multiple sheets.
Agree, this is using 3D referencing at the Excel level, not the VBA level and stores the desired "range" as a string. (preaching to the choir @DavidZemens, but clarifying for others who may stop by)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.