¡Jueves de post! Vengo con un post hoy un tanto interesante,
que surgió de una consulta y que viene a resolver una problemática muy común en
los diferentes informes de Power BI relacionados con RR.HH. La pregunta es,
¿cómo podemos saber el número de trabajadores activos en nuestra empresa en un periodo determinado?

A priori, es una pregunta muy sencilla, pero que depende de
cómo tengamos nuestro modelo de datos, puede llegar a complicarse. Vamos a ver cómo
resolver esta cuestión de una manera sencilla y práctica.



El modelo de datos que tenemos es el siguiente:



Tabla de dimensión de empleados:

 
 



IDTrabajador à
campo único y clave de negocio.



Categoría à
Atributo de la dimensión.



Al ser un modelo ficticio, pues no he añadido más atributos,
pero podemos tener los que necesitemos.



Y nuestra tabla de hechos, en la que tenemos registrados los
contratos de los trabajadores:



 
 


En la tabla podemos ver que tenemos las siguientes columnas:



IdContrato à
Campo único y clave de negocio



IdTrabajador à
Clave secundaria que relaciona la dimensión trabajador con la tabla hechos.



FechaInicio à
Columna con la fecha de inicio del contrato.



FechaFin à
Columna con la fecha fin de contrato. En caso de seguir estando en vigor, el
valor es null.



Una vez analizado nuestro modelo ficticio, vamos a Power BI
que es lo que nos gusta J



Lo primero que hacemos es generar nuestra dimensión fecha en
caso de no tenerla en un dataflow, que yo os recomiendo que la tengáis un
dataflow así podemos reutilizarla cada vez que lo necesitemos. Os dejo aquí el
link de cómo generarla.



En caso de no tener nuestra dimensión tiempo en un dataflow,
tenemos que generarla en nuestro modelo. Para ello en Power Query, vamos a
generar un parámetro y una consulta que vamos a usar para que esta dimensión
sea dinámica de manera que no tengamos que estar modificándola cada año.





Lo primero que hacemos es generar nuestro parámetro para la
fecha de inicio. En Power Query, en el panel de las consultas, hacemos click
con el botón derecho y luego hacemos click sobre Parámetro nuevo:





 


Y en la ventana que se nos abre, rellenamos los campos
Nombre, Tipo y Valor Actual con los datos que necesitemos para nuestro modelo.
En este caso, he usado los siguientes valores:



Nombre: FechaInicio



Tipo: Fecha



Valor Actual: 01/01/2020



 
 

Una vez tenemos definida nuestra fecha de inicio, debemos
definir nuestra fecha fin, ya que no tiene ningún sentido crear una dimensión
tiempo de 1000 años, ya que lo único que nos va a aportar es tamaño a nuestro
modelo. ¿No creéis? ¿Y hasta dónde calcumos la fecha fin de nuestra dimensión
tiempo? Hasta el final del año en curso, de esta manera conseguimos que sea
dinámica. Para eso creamos una consulta en blanco:

 


 



En el Editor que se nos ha desplegado, tenemos que obtener
el año en curso, para ello usamos la función Date.Year para la función
DateTime.LocalNow():



let



// Extraigo el año del sistema



Año = Date.Year(DateTime.LocalNow()),



 



¿Y cómo calculamos el final del año? Pues concatenando al
año calculado 31/12 ya que por ahora todos los años terminan siempre en la
misma fecha J
Para eso usamos la función Text.From:



 



Fecha = Text.From("31/12/")
& Text.From(Año),



 



Y ahora ya tenemos la fecha fin de la dimensión tiempo pero
en formato texto, por lo que la convertimos en tipo fecha con la función
Date.FromText:



FechaFin = Date.FromText(Fecha)



 



Y nos queda un código como el siguiente:

 
 



Ahora ya podemos calcular nuestra dimensión tiempo, para ello
lo primero que tenemos que hacer es calcular el número de días que hay entre la
fecha de inicio y la fecha fin que tenemos. Para ello usamos la función Duration.Days.
(le sumamos 1 ya que sólo tiene en cuenta una de las fechas del intervalo):



 



// Calculamos el intervalo de días



DiasIntervalo = Duration.Days( FechaFin - FechaInicio) +1 ,



 



Una vez tenemos el número de días que tenemos entre fechas,
tenemos que listarlos.  Para ello, usamos
la función List.Dates:



 



// listamos las fechas del
intervalo



Fecha = List.Dates(FechaInicio,DiasIntervalo,
#duration(1,0,0,0)),



 



A continuación, lo convertimos en lista mediante la función
Table.FromList, que nos la genera automáticamente la interfaz de usuario:



 



//  Convertimos en tabla la lista



  #"Convertido en
tabla" = Table.FromList(Fecha, Splitter.SplitByNothing(), null, null,
ExtraValues.Error),



 



Ahora renombramos la columna 1 por Fecha:



 



// Cambiamos el nombre de la
columna 1



  #"Columnas con
nombre cambiado" = Table.RenameColumns(#"Convertido en tabla",
{{"Column1", "Fecha"}}),



 



Y le cambiamos el tipo a la columna para que sea tipo Fecha:



 



// Cambiamos el tipo de la
columna



    #"Tipo de columna cambiado" =
Table.TransformColumnTypes(#"Columnas con nombre cambiado",
{{"Fecha", type date}}),





 
 


Para crear una dimensión tiempo completa, insisto, te copio
aquí el link donde lo explico.



Una vez creada la dimensión tiempo, podemos pasar a la tabla
de hechos y analizarla. Vemos que la columna FechaFin viene con valores null si
no existe fecha fin de contrato en cuestión:

 
 
 


¿Y qué hacemos con esos valores? Pues un truquito que nos va
solucionar muchos problemas. Los vamos a sustituir esos valores por una fecha
futura, por ejemplo, el final del año próximo o lo que es lo mismo el
31/12/2024 y tenemos que hacer que este campo sea dinámico de manera que no lo
tengamos que modificar todos los años. ¿Y cómo lo hacemos? Pues de una manera
muy similar a cómo hemos obtenido la FechaFin pero con la salvedad que en el
primer paso cuando calculamos el año actual le sumamos 1:

 
 
 

De esta manera, cada vez que cambiemos de año,
automáticamente la fecha ficticia se nos va a actualizar. Ahora volvemos a la
tabla de hechos de contratos y reemplazamos los valores null por la fecha
ficticia:








 


Y ahora ya tenemos preparado nuestro modelo para calcular
los empleados activos en el período seleccionado.



Nota: Para este ejemplo no lo he hecho ya que es
ilustrativo, pero deberíamos generar nuestras propias claves subrogadas.



Una vez, ya hemos hecho nuestro tratamiento de los datos,
ahora ya podemos proceder a generar nuestras relaciones entre nuestras
dimensiones y nuestra tabla de hechos.

 
 
 
Fijaros que las relaciones entre nuestra dimensión Fecha y
nuestra tabla de hechos no están activas. Con esto lo que conseguimos se filtre
la tabla de hechos cuando filtremos un período en el informe y ser nosotros
mismos los que decidamos por qué relación queremos realizar el filtrar la
tabla.

Vamos a calcular el número de altas que se ha realizado en
la empresa, para eso creamos la siguiente métrica:



Altas =



CALCULATE (



    COUNTROWS ( FactContratos ),



    USERELATIONSHIP ( DimFecha[Fecha], FactContratos[FechaInicio] )



)



 



Lo que realizamos es un conteo del número de filas de la
tabla FactContratos y use la relación entre la tabla Fecha y la columna de
FechaInicio.





 
 


Pero se puede dar el caso de que tengamos un mismo
trabajador que se le haya acabado el contrato y este se haya prolongado. Para
ello calculamos la siguiente métrica:



Altas únicas =



CALCULATE (



    DISTINCTCOUNT (
FactContratos[IdTrabajador] ),



    USERELATIONSHIP (
DimFecha[Fecha], FactContratos[FechaInicio] )



)






En este caso, en vez de contar el número de líneas de la
tabla de hechos, usamos un DISTINCTCOUNT de la columna IdTrabajador de la tabla
de hechos y use la relación entre la tabla Fecha y la columna de FechaInicio:

 



Y como se puede ver, hemos tenido 60 contratos, pero de los
cuales 50 han sido a trabajadores diferentes, o lo que es lo mismo, a 10
trabajadores se les ha renovado el contrato en algún momento.



Ahora vamos a calcular en número de bajas que ha tenido la
empresa, es decir, el número de contratos que se han finalizado en algún
momento. Para ello generamos la siguiente métrica:



 



Bajas en periodo =



VAR UltimaFecha =



    LASTDATE (
DimFecha[Fecha] )



Return



CALCULATE (



    COUNTROWS (
FactContratos ),



    FactContratos[FechaFin]<=
UltimaFecha,



    USERELATIONSHIP (
DimFecha[Fecha], FactContratos[FechaFin] )



)



 Aquí creamos una variable con el valor de la última fecha
seleccionada, y contamos el número de filas de la tabla de hechos en los que la
columna FechaFin sea menor o igual a la fecha seleccionada y que la relación
con nuestra tabla de hechos sea mediante la columna FechaFin.

 
 
  
Pero aquí estamos en el mismo punto que con las altas. Aquí
pueden existir trabajadores que se les haya finalizado 2 o más veces el
contrato, por lo que si queremos obtener el número real de trabajadores que han
causado baja realizamos la siguiente métrica:

Bajas únicas en periodo =



 



VAR UltimaFecha =



    LASTDATE ( DimFecha[Fecha] )





Return



CALCULATE (



    DISTINCTCOUNT(FactContratos[IdTrabajador]),



    FactContratos[FechaFin]<=
UltimaFecha,



    USERELATIONSHIP ( DimFecha[Fecha], FactContratos[FechaFin] )



)



Lo mismo para esta métrica que para las altas únicas,
realizamos un DISTINCTCOUNT sobre la columna IdTrabajador.

 


 Y ahora vamos a calcular el número de trabajadores activos
en la empresa. Para ello, creamos la siguiente métrica:

Nº Trabajadores activos =



 



VAR UltimaFecha =



    LASTDATE (
DimFecha[Fecha] )





RETURN



    CALCULATE (



        DISTINCTCOUNT(
FactContratos[IdTrabajador] ),



        FILTER (
FactContratos, ( FactContratos[FechaInicio] <= UltimaFecha ) ),



        FILTER (
FactContratos, ( FactContratos[FechaFin] >= UltimaFecha ) )



    )



 



 ¿Qué estamos haciendo en esta métrica? Estamos contando el
número único del IdTrabajador de la tabla de hechos FactContratos y como argumento de filtro de la función
CALCULATE, introducimos el iterador FILTER recorremos la tabla FactContratos en
las que la FechaInicio sea menor o igual a la variable UltimaFecha. E
introducimos un segundo argumento de filtro para la función CALCULATE (recordad
que se ejecutan como un AND lógico), el segundo argumento es otro  FILTER para recorrer la tabla FactContratos en
las que la FechaFin sea mayor o igual a la variable UltimaFecha. ¿Y por qué
mayor a UltimaFecha? Por qué acordaros que en Power Query hemos calculado una
fecha ficticia futura y la hemos introducido en la tabla de hechos en la
columna FechaFin cuyos valores eran null, de esta manera siempre los contratos
activos van a tener una fecha futura. Esta medida la llevamos a una gráfico y
como resultado obtenemos:






 
 

Y podemos ver que la empresa ha tenido altibajos en su masa
de personal y tenemos como resultado nuestro informe con nuestros trabajadores
activos:

 


 





En el que podemos ver que hemos tenido 60 nuevas altas en el
periodo seleccionado de las cuales 50 trabajadores han sido únicos, es decir, a
10 trabajadores se les ha prorrogado el contrato en el algún momento. A la vez
la empresa ha tenido 17 bajas, de las cuales 1 de ellas ha sido repetida, o lo
que es lo mismo a un trabajador se le ha prorrogado un contrato y uno de los
siguientes no se ha prorrogado, por tanto, tenemos 43 personas en activo en
este momento.



Y hasta aquí el post de hoy. Espero que os sea útil.

¡Nos vemos en los datos!
 

P.d: Si queréis profundizar en el tema, aquí os dejo un link a un post escrito por el MVP Francisco Mullor en el que trata el mismo tema y lo complementa.