Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprende Procesamiento Eficiente de Datos | Trabajando con datos de Excel
Excel VBA para Automatización Empresarial

Procesamiento Eficiente de Datos

Desliza para mostrar el menú

Hasta ahora, todo ha funcionado una celda a la vez — adecuado para cinco pedidos, pero extremadamente lento para cincuenta mil. La solución es dejar de manipular la hoja celda por celda y, en su lugar, mover todo el bloque a un array en memoria, trabajar allí y luego escribirlo de vuelta de una sola vez.

Lectura de un rango en un array

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

dataArr es ahora un array bidimensional en memoria: dataArr(1,1) es ORD1001, dataArr(1,4) es "Laptop Stand", y así sucesivamente — los arrays de VBA leídos desde un rango son base 1, no base 0, lo cual suele causar confusión.

Procesamiento del array

Se realiza con bucles ordinarios — pero ahora se recorre la memoria, lo que es miles de veces más rápido que recorrer la hoja de cálculo:

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

Escritura del array de vuelta

Nuevamente, una sola operación:

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

Evitar Select y Activate

Las macros grabadas dependen mucho de estos (Range("A1").Select luego Selection.Font.Bold = True), pero son innecesarios y lentos: cada .Select obliga a Excel a volver a dibujar la pantalla. Referenciar el rango u objeto directamente en su lugar:

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

Consideraciones de rendimiento

Estas son importantes cuando tus datos superan unas pocas centenas de filas:

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

Siempre restaura estas configuraciones al final — y envuelve la restauración en manejo de errores para que, si ocurre un fallo durante la ejecución, Excel no quede con la actualización de pantalla desactivada.

Ejemplo práctico: el verificador de integridad de pedidos

Este capítulo ha estado construyendo hacia esto:

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

Ejecuta esto contra la tabla de ejemplo y debería informar que los cinco totales son correctos — prueba cambiando el Total de ORD1002 en la hoja a un valor incorrecto y vuelve a ejecutar para ver la alerta.

Tarea

  1. Copia VerifyOrderTotals en tu libro de trabajo y ejecútalo con los cinco pedidos de ejemplo.
  2. Rompe manualmente el Total de un pedido en la hoja (escribe un número obviamente incorrecto) y vuelve a ejecutar — confirma que la discrepancia se informa con el Order ID correcto.
  3. Agrega diez filas más de datos de pedidos inventados debajo de la fila 6 y confirma que la macro sigue funcionando sin cambios en el código — esto demuestra la utilidad de lastRow y el procesamiento por arrays.
Ayuda
expand arrow

Ayuda opcional si prefieres generar las diez filas adicionales mediante código en lugar de escribirlas manualmente:

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
Pista
expand arrow

1. Copiar VerifyOrderTotals

  • Escribe el Sub exactamente como se muestra en la sección 3.5 en el módulo de tu libro de trabajo — no es necesario realizar cambios por ahora.
  • Ejecútalo una vez con las cinco filas originales y confirma que obtienes "All 5 order totals check out."

2. Romper un Total a propósito

  • Elige cualquier celda de Total de un pedido y escribe un número obviamente incorrecto directamente en la hoja (no mediante código).
  • Vuelve a ejecutar el mismo Sub — el mensaje de discrepancia debe mostrar ese ID de pedido exacto, junto con lo que dice la hoja frente a lo que recalculó la macro.
  • Corrige la celda después si deseas una hoja limpia para el siguiente paso.

3. Agregar diez filas más

  • Simplemente escribe nuevos datos de pedidos directamente en las filas 7–16 — las mismas nueve columnas, cualquier valor creíble.
  • No modifiques la macro en absoluto. lastRow se recalcula cada vez que se ejecuta el Sub, y la lectura del array (ws.Range("A2:I" & lastRow).Value) se ajusta automáticamente — ese es el punto principal que se está demostrando.
Solución
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
¿Todo estuvo claro?

¿Cómo podemos mejorarlo?

¡Gracias por tus comentarios!

Sección 3. Capítulo 5

Pregunte a AI

expand

Pregunte a AI

ChatGPT

Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla

Sección 3. Capítulo 5
some-alt