martes, 12 de abril de 2022

VBA: CallByName - pasar texto como variable

Un problema habitual con el que nos encontramos es cuando al trabajar sobre un volumen alto de campos o columnas, necesitamos recuperar algunas de ellas... optando por la vía fácil de crear una línea por variable (fácil y ágil).
Por supuesto existen algunas alternativas, y hoy veremos una de ellas.

Supongamos un tabla con muchos campos, en el ejemplo nos quedaremos con una columna por mes:
VBA: CallByName - pasar texto como variable


El objetivo es recuperar las empresas solo de 'ES' y sus datos acumulados por trimestre y año (operaciones que realizará la macro).

Para ello nos apoyaremos en la función VBA (poco conocida) CallByName que ejecuta un método de un objeto, o bien establece o devuelve una propiedad de un objeto.
Su sintáxis:
CallByName( objecto , procname, calltype [, args()])

Objeto: (obligatorio). Tipo Object. El nombre del objeto en el que se ejecutará la función.
procname:(obligatorio). Tipo String. Expresión de cadena que contiene el nombre de una propiedad o método del objeto.
calltype: (bligatorio). Tipo Constante. Una constante de tipo vbCallType que representa el tipo de procedimiento al que se llama.
args(): (opcional). Tipo Variant(matriz).

Para facilitar la conversión y el tratamiento de objetos crearemos un Módulo de clase con una sencilla línea:
Public dato As Variant

A este módulo de clase lo he llamado 'clsEMP'

Ya podemos desarrollar nuestro código en un módulo estándar:
Sub PasarTextoComoVariable_OLD()
'nos referimos a la tabla de la hoja1
Set tb = Hoja1.ListObjects(1)
Dim arrFINAL() As Variant   'definimos la matriz final que recopilará los datos que nos interesen

'comenzamos el bucle por la tabla
x = 0
For Each emp In Hoja1.Range("TblDATOS[empresa]")
    x = x + 1
    'aplicamos la condición del país buscado
    If UCase(Hoja1.Range("TblDATOS[País]").Item(x).Value) = "ES" Then
        'y asignamos valor a nuestras 19 variables
        '(y, sí... hay otra forma de hacerlo más sencillo)
        empresa = tb.DataBodyRange.Cells(x, tb.ListColumns("empresa").Index).Value
        pais = tb.DataBodyRange.Cells(x, tb.ListColumns("país").Index).Value
        ene = tb.DataBodyRange.Cells(x, tb.ListColumns("ene").Index).Value
        feb = tb.DataBodyRange.Cells(x, tb.ListColumns("feb").Index).Value
        mar = tb.DataBodyRange.Cells(x, tb.ListColumns("mar").Index).Value
        Q1 = ene + feb + mar
        abr = tb.DataBodyRange.Cells(x, tb.ListColumns("abr").Index).Value
        may = tb.DataBodyRange.Cells(x, tb.ListColumns("may").Index).Value
        jun = tb.DataBodyRange.Cells(x, tb.ListColumns("jun").Index).Value
        Q2 = abr + may + jun
        jul = tb.DataBodyRange.Cells(x, tb.ListColumns("jul").Index).Value
        ago = tb.DataBodyRange.Cells(x, tb.ListColumns("ago").Index).Value
        sep = tb.DataBodyRange.Cells(x, tb.ListColumns("sep").Index).Value
        Q3 = jul + ago + sep
        octb = tb.DataBodyRange.Cells(x, tb.ListColumns("oct").Index).Value
        nov = tb.DataBodyRange.Cells(x, tb.ListColumns("nov").Index).Value
        niv = tb.DataBodyRange.Cells(x, tb.ListColumns("dic").Index).Value
        Q4 = octb + nov + dic
        YYYY = Q1 + Q2 + Q3 + Q4
        
        'matriz con los datos que nos interesa trabajar
        Dim arr() As Variant
        arr = Array(empresa, Q1, Q2, Q3, Q4, YYYY)
        'recorremos los campos a recuperar
        For i = LBound(arr) To UBound(arr)
            'creando un objeto con cada uno de ellos
            Set valor = New clsEMP	'usamos nuestro módulo de clase
            valor.dato = arr(i) 'cargamos el objeto con el valor asignado
            'para finalmente con CallByName obtener el valor del objeto
            'y asignarlo a nuestra matriz final
            ReDim Preserve arrFINAL(0 To 5, 0 To incremento) As Variant
            arrFINAL(i, incremento) = CallByName(valor, "dato", VbGet)
                       
        Next i
        incremento = incremento + 1
        Set valor = Nothing
        
    End If
Next emp

'devolvemos los datos a la hoja...
Hoja1.Range("B10").Resize(incremento, 6).Value = Application.Transpose(arrFINAL())


Set tb = Nothing
End Sub

Un buen método de trabajo si el número de variables con el trabajar es alto; además es bastante claro, ya que quedan muy detalladas en cuanto número, nombre y orden en nuestra matriz 'arr'.

Una alternativa más que conviene considerar.

No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.