¡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.