lunes, octubre 02, 2017

Reducción de valores mostrados en lista desplegable con criterio de búsqueda

Como ya hemos mostrado en este blog, hay muchas formas de crear listas desplegables en Excel:
  • con Validación de Datos, Lista;
  • incrustando en la hoja un cuadro combinado (combobox) o un cuadro de lista (listbox) de la colección de formularios;
  • programando un cuadro combinado o un cuadro de lista en un Userform en el editor de Vba (macros).
Todas las técnicas pueden verse en mi e-book "Listas Desplegables - la guía JLD".

Uno de los requerimientos de los usuarios es la posibilidad de reducir los valores que aparecen en la lista de acuerdo a algún criterio. Supongamos que tenemos una lista de varios cientos de productos y queremos ver sólo aquellos que contengan la palabra "aceite" antes de seleccionar los valores deseados.

En este post voy a mostrar cómo hacerlo usando un ListBox para crear la lista desplegable y un cuadro de texto para introducir el texto del criterio de búsqueda. Todo ésto lo armamos en un Userform y, por supuesto, usaremos código de Vb para activar el modelo.

Esta captura de pantalla  muestra como funciona nuestro modelo. Cada vez que ingresamos un valor en la casilla de textos, la lista desplegable se reduce a los valores que contienen ese texto




El origen de los datos de la lista desplegable es una lista de precios que se encuentra en una tabla que llamaremos "tbl_Productos"


No me voy a extender aquí sobre las bondades de usar Tablas para organizar nuestros datos en las hojas de Excel, tema que he tocado varias veces en este blog.

Creamos un Userform con un cuadro de lista (Listbox), un cuadro de texto (Textbox) y dos botones de comando


Cuando incrustamos el cuadro de lista (Listbox) en el formulario, definimos ciertas propiedades en la ventana de propiedades


Como puede apreciarse RowSource (la fuente de los datos de la lista) se refiere directamente a la tabla con su nombre.
Para facilitar el código que mostramos más adelante, creamos también un nombre definido que se refiere a la tabla


Los códigos detrás de los objetos (que van en el módulo del Userform) son los siguientes:

# - un evento Change para el ListBox. Este evento se dispara cada vez que tecleamos algún valor en la casilla de texto; cuando esta vacía vemos todos los valores de la lista de precios


 Private Sub tboxCriterio_Change()  
   Dim v As Variant, i As Long  
   v = Range("lstProductos").Value  
   With Me.lbxProductos  
   If Len(Me.tboxCriterio.Value) = 0 Then  
     .RowSource = "lstProductos"  
   Else  
     .RowSource = ""  
     For i = LBound(v, 1) To UBound(v, 1)  
       If LCase(v(i, 1)) Like "*" & LCase(tboxCriterio.Value) & "*" Then  
         .AddItem v(i, 1)  
         .List(.ListCount - 1, 1) = v(i, 2)  
       End If  
     Next i  
   End If  
   End With  
 End Sub  


# - un evento Click para el botón Cancelar

 Private Sub cbtCancelar_Click()  
   Unload ufProductos  
 End Sub  

Si estuviéramos usando este formulario en un modelo real tendríamos que escribir código para el botón Aceptar. Aquí estamos mostrando solamente cómo crear la lista desplegable así que dejaremos ese código para algún post en el futuro (en caso que algunos de mis lectores quieran ver como aplicar esta técnica a un ejemplo).

Para activar el Userform usamos el botón "Lista de productos" al cua tiene asociado este código

 Sub listaProductos()  
   ufProductos.Show  
 End Sub  


jueves, septiembre 28, 2017

El misterioso caso de los números cambiantes (Excel y las definiciones regionales)

En algún post del pasado he mencionado que, en ciertas circunstancias, Excel tiende a ser más "amable" de lo deseado. En su afán de ayudarnos Excel toma decisiones y transforma datos a medida que los vamos ingresando en una celda. Por ejemplo, si ingresamos el valor 15/9 Excel supondrá que se trata de la fecha 15 de setiembre y agregará el año corriente resultando 15/09/2017.

Esta característica de Excel conlleva problemas potencialmente graves. El resultado de la transformación está ligada a las definiciones regionales del sistema (Windows). Por ejemplo, si las definiciones regionales de nuestro sistema son las de España e ingresamos 10/9 Excel lo transformará en 10/09/2017 de acuerdo al patrón de la definición (día/mes/año)


Pero si nuestras definiciones regionales son las de Estados Unidos


si bien veremos en la celda 10/9/2017, de acuerdo al patrón mes/día/año, la fecha ingresada es el 9 de octubre.

El problema no está limitado solamente a las fechas. Supongamos que nuestro sistema tiene definiciones regionales donde la coma es el separador de miles y el punto de los decimales. Ahora copiamos este valor de la tasa GBP/USD (libra esterlina / dólar americano) y lo pegamos en una celda de Excel


El resultado será el siguiente


El valor fue copiado de un sitio español donde el separador de decimales es la coma; pero en mi sistema la coma es el separador de miles. Si nos fijamos veremos que en la barra de las fórmulas aparece 13845 (trece mil ochocientos cuarenta y cinco) y en la celda Excel ha aplicado el formato de número.
¿Cómo solucionamos este problema? Si se trata de un valor podemos hacer un clic en el icono de las opciones de pegado y usar el asistente para importar texto

Vamos directamente al paso 3


y cambiamos en Avanzadas las definiciones de separador de decimal y separador de miles. Ésto solucionará el problema.

¿Y si se trata de una tabla con muchos valores? Lo solucionamos con la opción Texto en Columnas (Datos-Herramientas de Datos) o con Power Query, por supuesto, como mostraré en una próxima nota.

martes, septiembre 26, 2017

Cálculo de horas trabajadas con Power Query - tercera nota

En la primera nota vimos como calcular horas trabajadas por un empleado usando el Power Query. El objetivo del post era mostrar que lo que ya habíamos mostrado como hacerlo con Excel (fórmulas) podía hacerse también con Power Query.

En la segunda nota vimos las grandes ventajas que nos ofrece el uso de Power Query al hacer los cálculos combinando los informes de varios empleados, en forma automática y sin necesidad de recrear las fórmulas con cada nuevo informe.

En ambas notas mostramos el caso sencillo donde no hay que diferenciar las horas por turnos. En este post vamos a recrear el ejemplo del segundo pero agregando la necesidad de calcular cuántas de las horas trabajadas fueron en el turno diurno y cuántas en el turno nocturno.

De hecho vamos a estar recreando en Power Query el modelo que mostré en este post. La lógica aplicada es la misma pero "traducida al idioma" Power Query. Las ventajas, como ya expliqué en las notas anteriores, son:
  • la robustez del modelo: no hay fórmulas en celdas que puedan ser alteradas desapercibidamente;
  • la facilidad de combinar un gran número de fuentes de datos y crear informes;
  • actualización de los datos e informes con sólo apretar un botón.
Para este ejemplo vamos a usar los mismos archivos del segundo post (los informes de los empleados que guardamos en la carpeta Informes).
Al crear este nuevo modelo el primer paso es definir las horas de comienzo y finalización del turno noche. En una hoja de Excel ponemos esta sencilla tabla

Creamos una consulta a la tabla como "sólo conexión"


Podemos ver  PASOS APLICADOS que Power Query ha cambiado el tipo de dato de las columnas Comienza y Termina a número decimal (identificado por 1.2 a la izquierda del encabezado de la columna). Ésto sirve a nuestros propósitos así que lo aceptamos.

A partir de esta consulta creamos una nueva con la opción Referencia


Abrimos la nueva conulta y cambiamos el nombre a "noche_comienzo".Con un clic del botón derecho del mouse y apuntando al valor en la fila Comienza y activamos la opción "Rastrear desagrupando datos" (en inglés sencillamente, drill down)


con este resultado


Ahora guardamos esta consulta también como "sólo conexión". Repetimos el proceso para crear una consulta para el valor de "noche_final", esta vez seleccionando el valor de la columna Termina.
Nuestra hoja se ve ahora así


Ahora vamos a aplicar los pasos que aplicamos en la segunda nota para crear una consulta que integre todos los informes (archivos xlsx) guardados en la carpeta Informes. Al final de proceso tenemos esta consulta en la ventana del editor de PQ


Aquí vamos a hacer un pequeño cambio a lo que mostramos en la segunda nota. Vamos a extraer de Entrada y Salida le fecha y dejar sólo las horas. Para hacerlo seleccionamos ambas columnas y aplicamos en Transformar-Columna de Fecha y Hora-Solo hora


ahora tendremos


La próxima transformación que hacemos es transformar las horas de Entrada y Salida al tipo de datos número decimal.


Ahora vamos a aplicar la misma lógica que usamos en la solución con Excel tradicional

# - calculamos las horas trabajadas con una columna personalizada con esta fórmula

=if [Salida]<[Entrada] then
1+[Salida]-[Entrada]
else
[Salida]-[Entrada]

# agregamos dos columnas auxiliares "noche-comienzo"


y "noche-final" de la misma manera . Cambiamos el tipo de datos a número decimal.


# creamos una columna personalizada que llamaremos "Mediana - Entrada". Ésta es una columna auxiliar (con el mismo objetivo de la correspondiente columna en el modelo en Excel ya mencionado). Seleccionamos la columna Entrada y las dos columnas que acabamos de crear y creamos una nueva columna con Agregar Columnas-Estadísticas-Mediana


La columna creada recibe, por defecto, el nombre "Median" que vamos a reemplazar con "Mediana-Entrada". Ésto podemos hacerlo agregando un paso o, como muestro en la imagen abajo, reemplazando el valor en la ventana de las fórmulas


Hacemos lo mismo con Salida-noche_comienzo y noche_final para crear la columna "Mediana-Salida".

# creamos una nueva columna auxiliar, "aux1" con esta fórmula condicional

# ahora calculamos las horas trabajadas en el turno noche con esta fórmula:
[Horas trabajadas]+[#"Mediana-Entrada"]-[#"Mediana-Salida"]-[aux1]

# todo lo que nos queda por hacer es calcular las horas diurnas que, lógicamente, son la diferencia entre las horas trabajadas y las horas nocturnas

# Finalmente eliminamos todas las columnas auxiliares que creamos y dejamos solamente aquellas que queremos que aparezcan en nuestro informe


Transformamos las columnas de horas al tipo de dato "Hora" y cargamos la consulta a una hoja del cuaderno


Para crear un informe que resuma los datos por empleados empezamos por crear una nueva consulta que cuyo origen es una referencia a la que acabamos de crear. Cambiamos el tipo de datos de las columnas de horas a número decimal y aplicamos "Agrupar por" de esta manera



Cargamos la consulta a una hoja del cuaderno y cambiamos el formato de las columnas de las horas al tipo personalizado [hh]:mm en el menú de formato de celdas de Excel (ver la explicación en la nota anterior).
Nuestro resumen se verá así