Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Learn Efficient Data Processing | Working with Excel Data
Excel VBA for Business Automation

Efficient Data Processing

Swipe to show menu

Everything so far has worked one cell at a time — fine for five orders, painfully slow for fifty thousand. The fix is to stop touching the worksheet cell-by-cell and instead move the whole block into an array in memory, work on it there, and write it back in one shot.

Reading a Range into an Array

Dim dataArr As Variant
dataArr = ws.Range("A2:I6").Value    ' one read, not 45 individual reads

dataArr is now a 2D array in memory: dataArr(1,1) is ORD1001, dataArr(1,4) is "Laptop Stand", and so on — VBA arrays read from a range are 1-based, not 0-based, which is a common trip-up.

Processing the Array

Happens with ordinary loops — but now you're looping over memory, which is thousands of times faster than looping over the worksheet:

Dim i As Long
Dim recalculated As Double
 
For i = 1 To UBound(dataArr, 1)
    recalculated = dataArr(i, 5) * dataArr(i, 6) * (1 - dataArr(i, 7))
    If Abs(recalculated - dataArr(i, 8)) > 0.01 Then
        Debug.Print "Mismatch on row " & i & ": sheet says " & dataArr(i, 8) & _
                    ", recalculated " & Format(recalculated, "0.00")
    End If
Next i

Writing the Array Back

Again a single operation:

ws.Range("A2:I6").Value = dataArr

Avoiding Select and Activate

Recorded macros lean on these heavily (Range("A1").Select then Selection.Font.Bold = True), but they're unnecessary and slow — every .Select forces Excel to redraw the screen. Reference the range or object directly instead:

' Avoid:
ws.Range("A1").Select
Selection.Font.Bold = True
 
' Prefer:
ws.Range("A1").Font.Bold = True

Performance Considerations

These matter once your data grows past a few hundred rows:

Application.ScreenUpdating = False   ' stop redrawing while the macro runs
Application.Calculation = xlCalculationManual   ' pause recalculation
Application.EnableEvents = False     ' suppress other macros triggering mid-run
 
' ... your fast array-based code here ...
 
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True

Always restore these settings at the end — and wrap the restoration in error handling so a mid-run crash doesn't leave Excel stuck with screen updating turned off.

Worked Example: the Order Integrity Checker

This chapter has been building toward this:

Option Explicit
 
Sub VerifyOrderTotals()
    Dim ws As Worksheet
    Dim dataArr As Variant
    Dim lastRow As Long
    Dim i As Long
    Dim recalculated As Double
    Dim issues As String
 
    Set ws = ThisWorkbook.Worksheets("Orders")
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
 
    Application.ScreenUpdating = False
 
    dataArr = ws.Range("A2:I" & lastRow).Value
    issues = ""
 
    For i = 1 To UBound(dataArr, 1)
        recalculated = dataArr(i, 5) * dataArr(i, 6) * (1 - dataArr(i, 7))
        If Abs(recalculated - dataArr(i, 8)) > 0.01 Then
            issues = issues & dataArr(i, 1) & ": sheet=" & dataArr(i, 8) & _
                      ", expected=" & Format(recalculated, "0.00") & vbNewLine
        End If
    Next i
 
    Application.ScreenUpdating = True
 
    If issues = "" Then
        MsgBox "All " & UBound(dataArr, 1) & " order totals check out."
    Else
        MsgBox "Discrepancies found:" & vbNewLine & issues
    End If
End Sub

Run this against the sample table and it should report all five totals as correct — try changing ORD1002's Total on the sheet to something wrong and re-run to see the alert fire.

Task

  1. Copy VerifyOrderTotals into your workbook and run it against the five sample orders.
  2. Manually break one order's Total on the sheet (type in an obviously wrong number) and re-run — confirm the mismatch is reported with the correct Order ID.
  3. Add ten more rows of made-up order data below row 6, and confirm the macro still works without any code changes — this is lastRow and array-processing paying off.
Helper
expand arrow

Optional helper if you'd rather generate the ten extra rows in code instead of typing them by hand:

Sub AddTestOrders()
    Dim ws As Worksheet
    Dim i As Long
    Dim r As Long

    Set ws = ThisWorkbook.Worksheets("Orders")
    r = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1

    For i = 1 To 10
        ws.Cells(r, 1).Value = "ORD" & (1005 + i)
        ws.Cells(r, 2).Value = Date
        ws.Cells(r, 3).Value = "Test Customer " & i
        ws.Cells(r, 4).Value = "Sample Product"
        ws.Cells(r, 5).Value = i
        ws.Cells(r, 6).Value = 20 + i
        ws.Cells(r, 7).Value = 0.05
        ws.Cells(r, 8).Value = i * (20 + i) * (1 - 0.05)
        ws.Cells(r, 9).Value = "Pending"
        r = r + 1
    Next i
End Sub
Hint
expand arrow

1. Copying VerifyOrderTotals

  • Type the Sub exactly as shown in section 3.5 into your workbook's module — no changes needed yet.
  • Run it once against the five original rows and confirm you get "All 5 order totals check out."

2. Breaking one Total on purpose

  • Pick any order's Total cell and type an obviously wrong number directly into the worksheet (not through code).
  • Re-run the same Sub — the mismatch message should name that exact Order ID, along with what the sheet says versus what the macro recalculated.
  • Fix the cell back afterward if you want a clean sheet for the next step.

3. Adding ten more rows

  • Just type new order data directly into rows 7–16 — same nine columns, any believable values.
  • Don't touch the macro at all. lastRow recalculates itself every time the Sub runs, and the array read (ws.Range("A2:I" & lastRow).Value) automatically grows to match — that's the entire point being demonstrated.
Solution
expand arrow
Option Explicit

Sub VerifyOrderTotals()
    Dim ws As Worksheet
    Dim dataArr As Variant
    Dim lastRow As Long
    Dim i As Long
    Dim recalculated As Double
    Dim issues As String

    Set ws = ThisWorkbook.Worksheets("Orders")
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row

    Application.ScreenUpdating = False

    dataArr = ws.Range("A2:I" & lastRow).Value
    issues = ""

    For i = 1 To UBound(dataArr, 1)
        recalculated = dataArr(i, 5) * dataArr(i, 6) * (1 - dataArr(i, 7))
        If Abs(recalculated - dataArr(i, 8)) > 0.01 Then
            issues = issues & dataArr(i, 1) & ": sheet=" & dataArr(i, 8) & _
                      ", expected=" & Format(recalculated, "0.00") & vbNewLine
        End If
    Next i

    Application.ScreenUpdating = True

    If issues = "" Then
        MsgBox "All " & UBound(dataArr, 1) & " order totals check out."
    Else
        MsgBox "Discrepancies found:" & vbNewLine & issues
    End If
End Sub
Everything was clear?

How can we improve it?

Thanks for your feedback!

Section 3. Chapter 5

Ask AI

expand

Ask AI

ChatGPT

Ask anything or try one of the suggested questions to begin our chat

Efficient Data Processing

Everything so far has worked one cell at a time — fine for five orders, painfully slow for fifty thousand. The fix is to stop touching the worksheet cell-by-cell and instead move the whole block into an array in memory, work on it there, and write it back in one shot.

Reading a Range into an Array

Dim dataArr As Variant
dataArr = ws.Range("A2:I6").Value    ' one read, not 45 individual reads

dataArr is now a 2D array in memory: dataArr(1,1) is ORD1001, dataArr(1,4) is "Laptop Stand", and so on — VBA arrays read from a range are 1-based, not 0-based, which is a common trip-up.

Processing the Array

Happens with ordinary loops — but now you're looping over memory, which is thousands of times faster than looping over the worksheet:

Dim i As Long
Dim recalculated As Double
 
For i = 1 To UBound(dataArr, 1)
    recalculated = dataArr(i, 5) * dataArr(i, 6) * (1 - dataArr(i, 7))
    If Abs(recalculated - dataArr(i, 8)) > 0.01 Then
        Debug.Print "Mismatch on row " & i & ": sheet says " & dataArr(i, 8) & _
                    ", recalculated " & Format(recalculated, "0.00")
    End If
Next i

Writing the Array Back

Again a single operation:

ws.Range("A2:I6").Value = dataArr

Avoiding Select and Activate

Recorded macros lean on these heavily (Range("A1").Select then Selection.Font.Bold = True), but they're unnecessary and slow — every .Select forces Excel to redraw the screen. Reference the range or object directly instead:

' Avoid:
ws.Range("A1").Select
Selection.Font.Bold = True
 
' Prefer:
ws.Range("A1").Font.Bold = True

Performance Considerations

These matter once your data grows past a few hundred rows:

Application.ScreenUpdating = False   ' stop redrawing while the macro runs
Application.Calculation = xlCalculationManual   ' pause recalculation
Application.EnableEvents = False     ' suppress other macros triggering mid-run
 
' ... your fast array-based code here ...
 
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True

Always restore these settings at the end — and wrap the restoration in error handling so a mid-run crash doesn't leave Excel stuck with screen updating turned off.

Worked Example: the Order Integrity Checker

This chapter has been building toward this:

Option Explicit
 
Sub VerifyOrderTotals()
    Dim ws As Worksheet
    Dim dataArr As Variant
    Dim lastRow As Long
    Dim i As Long
    Dim recalculated As Double
    Dim issues As String
 
    Set ws = ThisWorkbook.Worksheets("Orders")
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
 
    Application.ScreenUpdating = False
 
    dataArr = ws.Range("A2:I" & lastRow).Value
    issues = ""
 
    For i = 1 To UBound(dataArr, 1)
        recalculated = dataArr(i, 5) * dataArr(i, 6) * (1 - dataArr(i, 7))
        If Abs(recalculated - dataArr(i, 8)) > 0.01 Then
            issues = issues & dataArr(i, 1) & ": sheet=" & dataArr(i, 8) & _
                      ", expected=" & Format(recalculated, "0.00") & vbNewLine
        End If
    Next i
 
    Application.ScreenUpdating = True
 
    If issues = "" Then
        MsgBox "All " & UBound(dataArr, 1) & " order totals check out."
    Else
        MsgBox "Discrepancies found:" & vbNewLine & issues
    End If
End Sub

Run this against the sample table and it should report all five totals as correct — try changing ORD1002's Total on the sheet to something wrong and re-run to see the alert fire.

Task

  1. Copy VerifyOrderTotals into your workbook and run it against the five sample orders.
  2. Manually break one order's Total on the sheet (type in an obviously wrong number) and re-run — confirm the mismatch is reported with the correct Order ID.
  3. Add ten more rows of made-up order data below row 6, and confirm the macro still works without any code changes — this is lastRow and array-processing paying off.
Helper
expand arrow

Optional helper if you'd rather generate the ten extra rows in code instead of typing them by hand:

Sub AddTestOrders()
    Dim ws As Worksheet
    Dim i As Long
    Dim r As Long

    Set ws = ThisWorkbook.Worksheets("Orders")
    r = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1

    For i = 1 To 10
        ws.Cells(r, 1).Value = "ORD" & (1005 + i)
        ws.Cells(r, 2).Value = Date
        ws.Cells(r, 3).Value = "Test Customer " & i
        ws.Cells(r, 4).Value = "Sample Product"
        ws.Cells(r, 5).Value = i
        ws.Cells(r, 6).Value = 20 + i
        ws.Cells(r, 7).Value = 0.05
        ws.Cells(r, 8).Value = i * (20 + i) * (1 - 0.05)
        ws.Cells(r, 9).Value = "Pending"
        r = r + 1
    Next i
End Sub
Hint
expand arrow

1. Copying VerifyOrderTotals

  • Type the Sub exactly as shown in section 3.5 into your workbook's module — no changes needed yet.
  • Run it once against the five original rows and confirm you get "All 5 order totals check out."

2. Breaking one Total on purpose

  • Pick any order's Total cell and type an obviously wrong number directly into the worksheet (not through code).
  • Re-run the same Sub — the mismatch message should name that exact Order ID, along with what the sheet says versus what the macro recalculated.
  • Fix the cell back afterward if you want a clean sheet for the next step.

3. Adding ten more rows

  • Just type new order data directly into rows 7–16 — same nine columns, any believable values.
  • Don't touch the macro at all. lastRow recalculates itself every time the Sub runs, and the array read (ws.Range("A2:I" & lastRow).Value) automatically grows to match — that's the entire point being demonstrated.
Solution
expand arrow
Option Explicit

Sub VerifyOrderTotals()
    Dim ws As Worksheet
    Dim dataArr As Variant
    Dim lastRow As Long
    Dim i As Long
    Dim recalculated As Double
    Dim issues As String

    Set ws = ThisWorkbook.Worksheets("Orders")
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row

    Application.ScreenUpdating = False

    dataArr = ws.Range("A2:I" & lastRow).Value
    issues = ""

    For i = 1 To UBound(dataArr, 1)
        recalculated = dataArr(i, 5) * dataArr(i, 6) * (1 - dataArr(i, 7))
        If Abs(recalculated - dataArr(i, 8)) > 0.01 Then
            issues = issues & dataArr(i, 1) & ": sheet=" & dataArr(i, 8) & _
                      ", expected=" & Format(recalculated, "0.00") & vbNewLine
        End If
    Next i

    Application.ScreenUpdating = True

    If issues = "" Then
        MsgBox "All " & UBound(dataArr, 1) & " order totals check out."
    Else
        MsgBox "Discrepancies found:" & vbNewLine & issues
    End If
End Sub
Everything was clear?

How can we improve it?

Thanks for your feedback!

Section 3. Chapter 5
some-alt