jueves, 2 de septiembre de 2021

Power Query: Modificar un dato por fila y columna en la consulta

El artículo de hoy creo es de lo más interesante de la seríe de posts publicados sobre Power Query.
Ya que se trata de uno de los temas más preguntados en multitud de foros: cambiar el valor de un dato en particular, de una fila y columna concreta dentro de nuestra consulta.
Power Query: Modificar una dato por fila y columna en la consulta


Sí, seguro que has leído mucho sobre el tema y en la mayoría de los casos se nos dirige a una solución condicionada empleando Table.ReplaceValue... una buena solución, sin duda (puedes leer algo más en este otro post).

La parte negativa de este tip ode procesos es que necesitamos el apoyo de alguna condición, debiendo asegurarnos si fuera el caso de la unicidad del elemento...

Mi solución para evitar este problema es emplear Records, lo que nos aportará la flexibilidad que necesitamos...
Veamos cómo operar con este caso.
Cargaremos como siempre una tabla al editor de consultas de power Query (en mi caso solo como conexión).
Y a continuación abriremos el Editor avanzado donde escribiremos el siguiente código M:
let
    Origen = Excel.CurrentWorkbook(){[Name="TblDATOS"]}[Content],

    // Acción donde primero Eliminamos la fila 2 (recuerda que estamos en base 0 !!)
    //para seguidamente Insertar una nueva fila en el lugar de la anterior
    // con un registro compuesto por los nuevos valores
    // que modifican los previos existentes
    ValorModificado = Table.InsertRows(
        Table.RemoveRows(Origen,2,1),   //Elimina la fila 2
        2,          //insertamos una nueva fila en la posición 2
        //el valor de la fila compuesto por el siguiente Record
        ({Origen{2} & ([País="XXX"] & [Año=2021] &  [Unidades=Origen{2}[Unidades]*100])}))
in
    ValorModificado

Power Query: Modificar una dato por fila y columna en la consulta

Cuando la tabla original era:
Power Query: Modificar una dato por fila y columna en la consulta


Creo muy interesante la forma en que hemos modificado ciertos valores de esa fila de nuestra Tabla (tres en mi ejemplo... pero sin límite al respecto).
En primer lugar recuperamos la fila entera sobre la que estamos interesados... sin condiciones de ningún tipo:
Origen{2}, lo que nos devuelve la fila completa en forma de Record
Power Query: Modificar una dato por fila y columna en la consulta

Y ahora, a partir de ese Record, 'añadiremos' nuevos campos usando el operador de unión &:
{Origen{2} & ([País="XXX"] & [Año=2021] & [Unidades=Origen{2}[Unidades]*100])}
Mencionar que aunque esta técnica está pensada para añadir nuevos campos, cuando el campo nuevo añadido ya existe en el Record de origen, se produce una sustitución del valor de ese campo...esto es, a todos los efectos estamos cambiando una valor por otro!!
Fíjate que el tipo de dato nuevo puede ser de cualquier tipo: número, texto o incluso calculado a partir del mismo registro de partida :OO

Con el nuevo Record modificado ya creado, podemos hacer uso de dos funciones M muy sencillas y seguramente conocidas:
Table.RemoveRows(table as table, offset as number, optional count as nullable number) as table
que nos permite eliminar filas seguidas de una tabla... la posición de la fila a eliminar la indicamos en el segundo argumento (offset as number).
Y la otra función necesaria es:
Table.InsertRows(table as table, offset as number, rows as list) as table
la cual retorna una tabla con la/s filas insertada/s en nuestra tabla en la posición determinada, argumetno offset.
Cada columna de la fila que se va a insertar debe coincidir con los tipos de columna de la tabla !!! (no será un problema inicialmente para nuestro ejemplo)..

Combinando todo en la secuencia correcta, en una línea de código M hemos conseguido modificar o cambiar valores concretos de una fila y columna de nuestra consulta!.

Alternativamente, en lugar del método anterior para generar el nuevo Record, podemos usar otra función M:
Record.Combine(records as list) as record
función pensada para combina los registros en el elemento records determinado...
Pero curiosamente, realizando unas pruebas de otro tema, me percaté que ocurre lo mismo que en el método anterior...
Esto es, al intentar combinar el Record origen con los nuevos valores, los últimos modifican a los primeros:
let
    Origen = Excel.CurrentWorkbook(){[Name="TblDATOS"]}[Content],

    // Acción donde primero Eliminamos la fila 2 (recuerda que estamos en base 0 !!)
    //para seguidamente Insertar una nueva fila en el lugar de la anterior
    // con un registro compuesto por los nuevos valores
    // que modifican los previos existentes
    ValorModificado = Table.InsertRows(
        Table.RemoveRows(Origen,2,1),   //Elimina la fila 2
        2,          //insertamos una nueva fila en la posición 2
        //el valor de la fila compuesto por el siguiente Record
        {Record.Combine({ Origen{2}, [País="XXX"], [Año=2021],  [Unidades=Origen{2}[Unidades]*100] }) } )
in
    ValorModificado

LLegando nuevamente al resultado esperado!!

Un par de métodos que seguro te serán de muchísima utilidad para preparar la carga de tus datos ;-)

No hay comentarios:

Publicar un comentario

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