Home > Software engineering >  How can I build a summary table using values across several worksheets?
How can I build a summary table using values across several worksheets?

Time:06-09

I'm trying to pull data from cells in a set of other worksheets in the workbook into a summary table. The use case is that the workbook user creates and modifies a series of Details worksheets that are form-like with several cells that contain values such as Name and Age as well as more verbose information that is not needed for the summary.

So far, I've researched the following:

  • 3D References
    • This seems useful, but because the users of this workbook will be adding new detail sheets over time, I either have to create empty guard sheets and tell them not to mess with those, or hard code the names of the first and last detail sheets and again, tell them not to mess with those.
    • Regardless, it doesn't appear that you can directly use a 3D reference as the value of a formula. =Joe:John!A2 gives a value error rather than returning three rows.
  • UDF Returning a Range
    • The problem I'm running into here is how to actually return the values.
    • I can't just iterate through the sheets and build a Union(Result, CurrentRange) because that line throws a VB error that doesn't break in the debugger which results in an Excel Value Error.
    • I tried storing each of the values in a Collection then converting that to an Array with the first dim being the number of rows and the second dim being 1 column. When I try to set the .Value of the function's return Range, again, VB error as above.
  • I have not yet tried having the Function (or Sub in this case?) directly write the values by keeping track of the number of rows and moving through the Summary worksheet cell by cell. This feels really hacky, so I'm hoping it isn't the suggested solution.

I would love to be able to just pass a set of cell references and get a table, but I'd be happy to work with using a separate formula for each column in the summary to specify the value to collate.

I'm not asking for a working solution to be handed off, but I've hit so many dead ends and frustrating errors I'd be very happy with some solid leads. Thank you!

Here are some mockups of the structure of the workbook.

Sheet 1 is named Summary:

A B C D
1 Name Color
2 Joe Red
3 Jane Blue
4 John Black

The attempts with UDFs I mentioned above were trying to use the following formula in cell B2 on the summary sheet: =GetSummaryData("$D$4")

And here are three example detail sheets:

Joe

A B C D
1 Details
2
3 Name Age Gender Favorite Color
4 Joe 42 M Red
5
6 Biography
7 Lorem Ipsum

Jane

A B C D
1 Details
2
3 Name Age Gender Favorite Color
4 Jane 18 F Blue
5
6 Biography
7 Lorem Ipsum

John

A B C D
1 Details
2
3 Name Age Gender Favorite Color
4 Joe 99 M Black
5
6 Biography
7 Lorem Ipsum

Finally, here is some non-functional VBA code from my last attempt:

Option Explicit
Function PersonaSheetsData(RangeRef As String) As Range
    Dim result As Range, thisRange As Range, currSheet As Worksheet, col As New Collection
    For Each currSheet In ActiveWorkbook.Worksheets
        ' Guard to only pull data from Details worksheets
        If currSheet.Cells(1, 1) = "Details" Then
            Set thisRange = currSheet.Range(RangeRef)
            col.Add thisRange.Value
        End If
    Next currSheet
    Set result = ActiveCell
    Set result = result.Resize(col.Count, 1)
    Dim arr As Variant
    arr = collectionToArray(col)
    result.Value = arr
    Set PersonaSheetsData = result
End Function

Function collectionToArray(c As Collection) As Variant
    Dim a() As Variant: ReDim a(0 To c.Count - 1, 0 To 0)
    Dim i As Integer
    For i = 1 To c.Count
        a(i - 1, 0) = c.Item(i)
    Next
    collectionToArray = a
End Function

CodePudding user response:

This worked for me if you have an "auto-spill array formulas" version of Excel

Function PersonaSheetsData(RangeRef As String)
    Dim result As Range, thisRange As Range, currSheet As Worksheet, col As New Collection
    For Each currSheet In ActiveWorkbook.Worksheets
        ' Guard to only pull data from Details worksheets
        If currSheet.Cells(1, 1) = "Details" Then
            col.Add currSheet.Range(RangeRef).Value
        End If
    Next currSheet
    PersonaSheetsData = collectionToArray(col)
End Function

Function collectionToArray(c As Collection) As Variant
    Dim a() As Variant, i As Integer
    ReDim a(1 To c.Count, 1 To 1) '1-based feels more natural here...
    For i = 1 To c.Count
        a(i, 1) = c.Item(i)
    Next
    collectionToArray = a
End Function
  • Related