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
- Copia
VerifyOrderTotalsen tu libro de trabajo y ejecútalo con los cinco pedidos de ejemplo. - Rompe manualmente el
Totalde un pedido en la hoja (escribe un número obviamente incorrecto) y vuelve a ejecutar — confirma que la discrepancia se informa con elOrder IDcorrecto. - 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
lastRowy el procesamiento por arrays.
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
1. Copiar VerifyOrderTotals
- Escribe el
Subexactamente 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.
lastRowse recalcula cada vez que se ejecuta elSub, y la lectura del array (ws.Range("A2:I" & lastRow).Value) se ajusta automáticamente — ese es el punto principal que se está demostrando.
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
¡Gracias por tus comentarios!
Pregunte a AI
Pregunte a AI
Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla