lunes, junio 10, 2013

Tablas dinámicas – cambiar la función CONTAR por SUMA

Para totalizar los valores en los campos introducidos en el área de valores Excel utiliza la siguiente regla:


  • Si todos los valores en el campo (columna de la tabla de datos) de origen son numéricos, utiliza SUMA.
  • Si alguno de los valores no es numérico, utiliza CONTAR.


El problema con esta regla es que, a diferencia de la función SUMA usada en una celda de la hoja, las celdas vacías son consideradas no numéricas. Esto produce no pocos dolores de cabeza ya que basta que una de las celdas no contenga ningún valor para que la función usada para resumir los valores sea CONTAR.

El problema se agrava cuando tenemos varios campos de valores ya que Excel no cuenta con un método para cambiar la función de resumen de todos los campos de una sola vez. Si tenemos una tabla con muchos campos de valores, nuestro sufrido usuario deberá cambiar manualmente la función de cada uno de los campos.

En este ejemplo tenemos una tabla con los datos de una cadena de comercios para los meses de enero, febrero y marzo. Los datos son: zona, mes, número de visitantes, número de compradores (cuantos de los visitantes realizaron alguna compra) y ventas.



Como puede apreciarse, faltan los datos de marzo de la zona Sur, por lo que las celdas están vacías.

Al crear un reporte dinámico, veremos que Excel usa CONTAR para resumir los datos en lugar de SUMA, que era lo que esperábamos



En este estado de cosas podemos optar por una de estos tres caminos:


  1. modificar una a una la función de resumen
  2. rellenar las celdas vacías con ceros (lo que se puede hacer eficientemente con Ir a-Especial)
  3. usar esta macro para cambiar la función programáticamente:


Sub change_pt_function()
'Cambia la funcion de los campos de valor de CONTAR a SUMA
'Desarrollada por Jorge Dunkelman - JLDExcelsp.blogspot.com

    Dim pt As PivotTable
    Dim iDataFieldsCount As Integer
    Dim iX As Integer
       
    On Error Resume Next
    Set pt = ActiveCell.PivotTable
    On Error GoTo 0
   
    If pt Is Nothing Then
        MsgBox "La celda seleccionada no pertenece a una tabla dinamica", _
                    vbCritical, _
                    "Cambiar funcion en TD"
        Exit Sub
    End If
   
    iDataFieldsCount = pt.DataFields.Count
   
    For iX = 1 To iDataFieldsCount
        With pt.DataFields(iX)
            If .Function = xlCount Then
            .Function = xlSum
            .Name = Replace(.Name, "Cuenta de", "Suma de")
            End If
        End With
    Next iX
       
End Sub


Esta macro recorre todos los campos en el área de los valores; en caso que la función de resumen sea CONTAR, la reemplaza por SUMA.

Para usar la macro hay que seleccionar previamente alguna celda de la tabla dinámica, por eso usamos un MSgBox para informar al usuario en caso que no se haya seleccionado un celda de la tabla dinámica.
Otro detalle es que al usar la propiedad DataFields, el nombre del campo (label) no cambia al cambiar la función. Por eso, suponiendo que el usuario no ha cambiado el nombre por defecto del campo ("Cuenta de…"), reemplazamos "Cuenta de…" por "Suma de…" programáticamente.
Si no queremos cambiar los nombres de los campos, podemos poner un apóstrofe (') al comienzo de la sentencia .Name = Replace(.Name, "Cuenta de", "Suma de"), de manera que no sea ejecutada.

Para usar este código con comodidad podemos agregar un icono en la barra de acceso rápido.

sábado, junio 01, 2013

Hipervínculos dinámicos dentro de un cuaderno Excel

Hemos tratado el tema de los hipervínculos en Excel con bastante detalle (o como dicen algunos de mis más ibéricos lectores, "rizando el rizo"). Pero siempre queda algo en el tintero (o en rioplatense, "otra vuelta de tuerca").
En una nota pasada discutimos el tema de las referencias en los hipervínculos (absolutas y relativas). Pero, como decíamos, siempre queda algún detalle por tratar.

Por ejemplo, un lector me comenta que tiene un cuaderno con una hoja que sirve de plantilla. Esta hoja contiene hipervínculos a celda dentro de la misma hoja. Cada vez que crea una nueva hoja en el cuaderno a partir de la plantilla, los hipervínculos siguen refiriéndose a la plantilla y no a la nueva hoja.

Esto se debe que al crear el hipervínculo con Inserta-Vínculos-Hipervínculo (o con el menú contextual, o con el atajo de teclado), Excel guarda la información como texto que incluye la referencia a la hoja.

La solución es usar la función HIPERVINCULO con un pequeño truco. Si queremos que el hipervínculo apunte siempre a la celda E5, por ejemplo, de la hoja activa, usamos esta fórmula

=HIPERVINCULO("#E5","texto en la celda")

Al usar el símbolo # en la referencia a la celda, Excel apunta siempre a la celda en la hoja donde se encuentra la fórmula.

En este video, la hoja Plantilla contiene dos hipervínculos que apuntan a la celda E5. Uno creado con con Ctrl+Alt+K (en la celda B2, con el texto "estático") y el otro creado con la función HIPERVINCULO (en la celda B4, con el texto "dinámico"). Creamos una nueva hoja (Mover o Copiar-Crear Copia). Al pulsar el hipervínculo en la celda B2, volvemos a la celda E5 en la hoja Plantilla; al hacerlo en B4, llegamos a E5 en la hoja activa.


viernes, mayo 31, 2013

Encontrar la última celda en una hoja de Excel

Una de las tareas frecuentes al escribir código Vba, muchas veces al modificar código de una macro grabada, es tener que determinar la última fila (o celda o columna) usada en la hoja.
Si nos basamos en una macro que hemos grabado al usar el método Ir-Especial-Última celda,



veremos esta sentencia

Range("A1").SpecialCells(xlCellTypeLastCell).Select

El problema con este método es que Excel recalcula la ubicación de la última celda usada sólo cuando guardamos el archivo. Esto significa que si ingresamos un valor en una celda remota y luego lo borramos, Excel seguirá considerando esa celda como la última. Y como si esto no fuera poco, también si cambiamos el formato de una celda remota, aún si ingresar ningún valor, Excel la considerará la última celda usada.

Para asegurarnos de encontrar siempre la última celda usada, es decir, la celda más remota que contiene algún valor, tenemos que usar un código basado en el método Range.Find

Sub ultima_celda()
    Dim UltimaFila As Long

    If WorksheetFunction.CountA(Cells) > 0 Then

        UltimaFila = Cells.Find(What:="*", After:=[A1], _
              SearchOrder:=xlByRows, _
              SearchDirection:=xlPrevious).Row

         MsgBox UltimaFila, vbInformation, "Ultima fila"

    End If

End Sub


Este código encuentra la última celda y nos informa cuál es la fila con un mensaje.

Este video nos muestra la diferencia entre ambos métodos