You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VBA代码填充数组遇内存不足报错,公式无法正常生效求助

解决VBA数组赋值公式时的内存溢出与公式失效问题

问题描述

编写的VBA代码用于从多个年份工作表中按星期几计算两列数据的平均值,运行时在.Cells(iRow, iCol).Resize(UBound(a, 1), UBound(a, 2)).Formula = a行触发Out of Memory错误。修改数组声明后内存问题解决,但原本应执行的公式变成了纯字符串,无法进行计算。

原代码如下:

Sub Calculate_Averages()
    Dim e, ws As Worksheet, iYear As Integer, iRow As Integer, iCol As Integer, i As Integer, lr As Long
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
        With ThisWorkbook.Worksheets("Adverage")
            .UsedRange.Cells.Clear
            iCol = 2: iRow = 4
            For iYear = 2022 To 2018 Step -1
                ReDim a(1 To 10, 1 To 3) As String
                Set ws = ThisWorkbook.Worksheets(CStr(iYear))
                lr = ws.Cells(Rows.Count, "B").End(xlUp).Row
                If Not ws Is Nothing Then
                    a(1, 2) = ws.Name: a(1, 3) = ws.Name
                    a(2, 2) = "User 1": a(2, 3) = "User 2"
                    i = 0
                    For Each e In Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
                        i = i + 1
                        a(i + 2, 1) = e
                        a(i + 2, 2) = "=IFERROR(ROUND(AVERAGEIF('" & ws.Name & "'!$B$4:$B$" & lr & ",""" & e & """,'" & ws.Name & "'!$D$4:$D$" & lr & "),2),"""")"
                        a(i + 2, 3) = "=IFERROR(ROUND(AVERAGEIF('" & ws.Name & "'!$B$4:$B$" & lr & ",""" & e & """,'" & ws.Name & "'!$E$4:$E$" & lr & "),2),"""")"
                    Next e
                End If
                .Cells(iRow, iCol).Resize(UBound(a, 1), UBound(a, 2)).Formula = a
                iCol = iCol + 4
            Next iYear
        End With
    Application.Calculation = xlCalculationAutomatic
    Application.ScreenUpdating = True
End Sub

原因分析

  1. 内存溢出:原代码使用String类型数组存储公式字符串,一次性将整个数组写入单元格区域时,Excel解析大量公式字符串会占用过高内存,触发溢出错误。
  2. 公式变字符串:若将数组改为Variant类型,直接赋值.Value会让Excel把带等号的字符串识别为文本,而非可执行公式。

解决方案

方案1:拆分数组赋值,缓解内存压力

保留原String数组声明,将文本内容和公式内容拆分写入,减少单次操作的内存占用:

Sub Calculate_Averages()
    Dim e, ws As Worksheet, iYear As Integer, iRow As Integer, iCol As Integer, i As Integer, lr As Long
    Dim a(1 To 10, 1 To 3) As String
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    
    With ThisWorkbook.Worksheets("Adverage")
        .UsedRange.Cells.Clear
        iCol = 2: iRow = 4
        For iYear = 2022 To 2018 Step -1
            Set ws = ThisWorkbook.Worksheets(CStr(iYear))
            lr = ws.Cells(Rows.Count, "B").End(xlUp).Row
            If Not ws Is Nothing Then
                ' 填充文本与公式字符串
                a(1, 2) = ws.Name: a(1, 3) = ws.Name
                a(2, 2) = "User 1": a(2, 3) = "User 2"
                i = 0
                For Each e In Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
                    i = i + 1
                    a(i + 2, 1) = e
                    a(i + 2, 2) = "=IFERROR(ROUND(AVERAGEIF('" & ws.Name & "'!$B$4:$B$" & lr & ",""" & e & """,'" & ws.Name & "'!$D$4:$D$" & lr & "),2),"""")"
                    a(i + 2, 3) = "=IFERROR(ROUND(AVERAGEIF('" & ws.Name & "'!$B$4:$B$" & lr & ",""" & e & """,'" & ws.Name & "'!$E$4:$E$" & lr & "),2),"""")"
                Next e
                
                ' 分区域写入:先写文本,再写公式
                .Cells(iRow, iCol).Resize(UBound(a, 1), 1).Value = Application.Index(a, 0, 1)
                .Cells(iRow, iCol + 1).Resize(2, 2).Value = Application.Index(a, 1 To 2, 2 To 3)
                .Cells(iRow + 2, iCol + 1).Resize(7, 2).Formula = Application.Index(a, 3 To 9, 2 To 3)
            End If
            iCol = iCol + 4
        Next iYear
    End With
    
    Application.Calculation = xlCalculationAutomatic
    Application.ScreenUpdating = True
End Sub

方案2:使用Variant数组,强制识别公式

改用Variant数组,先写入所有内容,再对公式区域重新设置.Formula属性,强制Excel识别为可执行公式:

Sub Calculate_Averages()
    Dim e, ws As Worksheet, iYear As Integer, iRow As Integer, iCol As Integer, i As Integer, lr As Long
    Dim a(1 To 10, 1 To 3) As Variant
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    
    With ThisWorkbook.Worksheets("Adverage")
        .UsedRange.Cells.Clear
        iCol = 2: iRow = 4
        For iYear = 2022 To 2018 Step -1
            Set ws = ThisWorkbook.Worksheets(CStr(iYear))
            lr = ws.Cells(Rows.Count, "B").End(xlUp).Row
            If Not ws Is Nothing Then
                a(1, 2) = ws.Name: a(1, 3) = ws.Name
                a(2, 2) = "User 1": a(2, 3) = "User 2"
                i = 0
                For Each e In Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
                    i = i + 1
                    a(i + 2, 1) = e
                    a(i + 2, 2) = "=IFERROR(ROUND(AVERAGEIF('" & ws.Name & "'!$B$4:$B$" & lr & ",""" & e & """,'" & ws.Name & "'!$D$4:$D$" & lr & "),2),"""")"
                    a(i + 2, 3) = "=IFERROR(ROUND(AVERAGEIF('" & ws.Name & "'!$B$4:$B$" & lr & ",""" & e & """,'" & ws.Name & "'!$E$4:$E$" & lr & "),2),"""")"
                Next e
                
                ' 先写入所有内容(此时公式为文本)
                .Cells(iRow, iCol).Resize(UBound(a, 1), UBound(a, 2)).Value = a
                ' 强制将公式区域识别为可执行公式
                .Cells(iRow + 2, iCol + 1).Resize(7, 2).Formula = .Cells(iRow + 2, iCol + 1).Resize(7, 2).Value
            End If
            iCol = iCol + 4
        Next iYear
    End With
    
    Application.Calculation = xlCalculationAutomatic
    Application.ScreenUpdating = True
End Sub

关键提示

  • 拆分赋值的核心是降低单次写入操作的内存负载,避免Excel因一次性解析大量公式字符串而溢出。
  • 使用Variant数组时,二次设置.Formula属性是关键,这会让Excel重新解析单元格内容,将文本格式的公式转为可执行状态。

内容的提问来源于stack exchange,提问作者YasserKhalil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 13:24:25