Search code examples
excelexcel-2013vba

Excel ran out of resources while attempting to calculate one or more formulas


I have a workbook to do 'smart'-graphs on my expenses. It's been running for a year and there are now a lot of graphs and expenses. Excel now throws an out-of-resources error whenever I change anything or open the workbook. Thing is, I have lots of resources and its not using hardly any of them.

Win8 64bit w/ 8 core CPU and 32GB of ram
Office 2013 64bit

I have 2 sheets, the first sheet called Expenses has 3 columns [Date,Description,Amount] and about 1500 rows of data. The second sheet has a LOT (500 or so) of formulas that are all the same and aim to do "Sum all expenses between date X and Y where description matches -some needle-". The formula I have is this:

=
ABS(
    SUMPRODUCT(
        --(Expenses!A:A >= DATE(2011,12,1)), 
        --(Expenses!A:A < DATE(2012,1,1)), 
        --(ISNUMBER(FIND(C50,Expenses!B:B))),
        Expenses!C:C
    )
)

Can I give Excel more resources? (I'm happy for it to use all my ram, and chug my CPU for a few minutes).

Is there a more efficient way I can do this formula?

I understand that this formula is creating a large grid and masking my expenses list with it, and that for each formula this grid has to get created. Should I create a macro to do this more efficiently instead? If I had a macro, I would want to call it from a cell somehow like

=sumExpenses(<startDate>, <endDate>, <needle>)

Is that possible?

Thanks.


Solution

  • I had a go at creating a function that hopefully replicates what your current equation does in VBA with a few differences. Since I don't know the specifics of your second sheet the caching might not help at all.

    If your second sheet uses the same date range for all calls to sumExpenses then it should be a bit quicker as it pre-sums everything on the first pass, If your date range changes throughout then its just doing a lot of work for nothing.

    Public Cache As Object
    Public CacheKey As String
    
    Public Function sumExpenses(ByVal dS As Date, ByVal dE As Date, ByVal sN As String) As Variant
    Dim Key As String
    Key = Day(dS) & "-" & Month(dS) & "-" & Year(dS) & "_" & Day(dE) & "-" & Month(dE) & "-" & Year(dE)
    
        If CacheKey = Key Then
            If Not Cache Is Nothing Then
                If Cache.Exists(sN) Then
                    sumExpenses = Cache(sN)
                    Exit Function
                End If
                Set Cache = Nothing
            End If
        End If
        CacheKey = Key
        Set Cache = CreateObject("Scripting.Dictionary")
    
        Dim Expenses As Worksheet
        Dim Row As Integer
        Dim Item As String
    
        Set Expenses = ThisWorkbook.Worksheets("Expenses")
    
        Row = 1
    
        While (Not Expenses.Cells(Row, 1) = "")
            If Expenses.Cells(Row, 1).Value > dS And Expenses.Cells(Row, 1).Value < dE Then
                Item = Expenses.Cells(Row, 2).Value
                If Cache.Exists(Item) Then
                    Cache(Item) = Cache(Item) + Expenses.Cells(Row, 3).Value
                Else
                    Cache.Add Item, Expenses.Cells(Row, 3).Value
                End If
            End If
            Row = Row + 1
        Wend
    
        If Cache.Exists(sN) Then
            sumExpenses = Cache(sN)
        Else
            sumExpenses = CVErr(xlErrNA)
        End If
    
    End Function
    
    Public Sub resetCache()
        Set Cache = Nothing
        CacheKey = ""
    End Sub