Reemplazar varios valores a la vez en varias columnas al mismo tiempo.

Reemplazar varios valores a la vez en varias columnas al mismo tiempo.

Continuamos nuestra serie de tips de power query con un doble tip que nos puede ahorrar muchísimo trabajo.

¿Os habéis encontrado alguna vez la necesidad de reemplazar varias cadenas de valores en varias columnas diferentes?

Al final nos encontramos un montón de pasos de valor reemplazado. Vamos a ver algunos trucos para automatizar este proceso.

Pues bien, nos encontramos con una base de datos en la que en origen nos presenta las vocales acentuadas sin tilde y entre @ y la Ñ la muestra como @N@

Aquí un ejemplo

Y ese error tipográfico en origen aparece en cada uno de los campos de texto en los que hay elementos con tilde o Ñ. Haciéndolo manualmente tendría que hacer mínimo 6 transformaciones por cada tabla, contando con que tengo que modificar el código para coger más de una columna donde hacerlo o seleccionarlas una a una.

Vamos a ver la forma de:

  1. Aplicar una función para que me realice todos los reemplazos a la vez.
  2. Que esa función se aplique en cada una de las columnas que yo seleccione de una manera más sencilla que con ctrl: Eligiendo las columnas con elegir columna.

La función de reemplazo.

1º Vamos a crear una tabla con los reemplazos con una columna Find y otra Replace

Quedaría así:

Y este es el código usado con Especificar Datos:

let
    Origen = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WcnB0UNJROtyoFKsD5LiCOZ0QjieY0wvh+IM5kyGcUDBnFoTjB+ZMVIqNBQA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Find = _t, Replace = _t])
in
    Origen

En 2º lugar creamos nuestra función.

La función la he cogido del blog de Jhon MacDougall, MVP Microsoft https://www.howtoexcel.org/power-query/bulk-replace-values/ y es relativamente sencilla de entender. He puesto en castellano los comentarios para mejor comprensión:

¡!IMPORTANTE!! siempre que compartáis en la red algo que no es vuestro nunca está de más hacer la mención de la fuente.


 let 
BulkReplace = (DataTable as table, FindReplaceTable as table, DataTableColumn as list) =>
    let
        //Convertimos la tabla  FindReplaceTable en una lista usando la función Table.ToRows 
                FindReplaceList = Table.ToRows(FindReplaceTable),
        //Contamos el numero de filas en la tabla FindReplaceTable para determinar
        //cuantas iteraciones necesitaremos
        Counter = Table.RowCount(FindReplaceTable),
        //Definimos una función de iteración sobre la lista
        //con la función Table.ReplaceValue 
        BulkReplaceValues = (DataTableTemp, n) => 
        let 
            //Reemplazamos los valores usando  usando el nth item en FindReplaceList
            ReplaceTable = Table.ReplaceValue(
                DataTableTemp,
                /reemplazamos nulos por vacíos en nth item
                if FindReplaceList{n}{0} = null then "" else FindReplaceList{n}{0},
                if FindReplaceList{n}{1} = null then "" else FindReplaceList{n}{1},
                Replacer.ReplaceText,
                DataTableColumn
                )
        in
            //Si no estamos en el final de FindReplaceList
            //entonces seguimos iterando Table.ReplaceValue de nuevo
            if n = Counter - 1 
                then ReplaceTable
                else @BulkReplaceValues(ReplaceTable, n + 1),
        /evaluamos la subfunción desde la primera fila
        Output = BulkReplaceValues(DataTable, 0)   
    in
        Output
in
    BulkReplace

Ya tenemos nuestra tabla de reemplazos y tenemos nuestra función para reemplazar, ya solo queda invocar la función.

Para ello insertaremos un nuevo paso en la tabla donde queramos realizar el reemplazo.

A nuestra tabla de reemplazos la he llamado “Reemplazos” y a la función la he llamado fxReemplazar

Pulso en fx tras el último paso y llamo a la función de la siguiente forma:

= fxReemplazar(#»Tipo cambiado», Reemplazos, {«DAT_ENTIDAD_FEDERATIVA»})

Donde fxReemplazar es el nombre de nuestra función

“Tipo cambiado” el nombre del último paso

Reemplazos el nombre de la tabla donde tengo los valores que quiero reemplazar

y  DAT_ENTIDAD_FEDERATIVA es la columna sobre la que quiero hacer los reemplazos.

El primer objetivo conseguido: reemplazar varios valores al mismo tiempo sin tener que llamar cada vez a la función de reemplazar valores, pero lo hemos hecho sobre una sola columna y queremos hacerla sobre varias al mismo tiempo. Para ello vamos a poner en juego la función Table.ColumnNames que devuelve una lista de los nombres de las columnas de la tabla.

Si en el código sustituimos {«DAT_ENTIDAD_FEDERATIVA»}) por Table.ColumnNames(#»Tipo cambiado») realizaría la sustitución por todas y cada uno de las columnas de nuestra tabla tal y como estuviera en el paso anterior.

El problema de esto es que en todas aquellas columnas en las que el tipo de datos no fuera texto nos daría error:

Lo que vamos a hacer entonces es crear un paso anterior en el que con “Elegir columnas” vamos a elegir aquellas donde queremos que nos realice la búsqueda y reemplazo

Automáticamente nuestro siguiente paso de invocación de la fórmula cambia a esta manera

= fxReemplazar(#»Otras columnas quitadas», Reemplazos, Table.ColumnNames(#»Otras columnas quitadas»))

Y nuestra nueva tabla nos muestra las columnas que hemos elegido con las sustituciones realizadas:

Obsérvese Estado de México correctamente.

Pero claro, necesitamos todas las columnas que hemos perdido al elegir las columnas, pero con Power Query podemos hacer un poco de magia y para obviar el paso de Elegir columnas, pero sin eliminarlo porque nos sirve llamar las columnas donde queremos realizar los reemplazos, simplemente cambiando el nombre del paso de origen en nuestra función obtenemos nuestro objetivo.

Es decir en = fxReemplazar(#»Otras columnas quitadas», Reemplazos, Table.ColumnNames(#»Otras columnas quitadas»))

Sustituimos #»Otras columnas quitadas», por #»Tipo cambiado», que es justo el paso anterior a la elección de columnas de manera que nos saltamos el paso de elección de columnas, que no lo tiene en cuenta como tal, pero si lo tiene en cuenta a la hora de realizar el reemplazo

Este sería como quedaría definitivamente nuestro código.

Os adjunto un pbix con un set de datos más pequeñito pero en el que podéis ver los resultados ya que no puedo pasaros el contenido del original sobre el que he hecho el ejemplo.

FranM

3 comentarios

rt Publicado el6:36 am - 05/10/2021

buenos dias fran
yo tengo una pregunta mas sencilla

tengo una columna con 40 valores y quiero borrar todos menos 4

si filtro y pongo solo esos 4 la tabla pasa de 3000 a 158 registros y lo que quiero es eliminar todos los valores que no sean bic, intel, energy o microsoft de la columna y que lo haga automaticamente cada vez que cargue una tabla nueva.

me puedes ayudar

Francisco Mullor Publicado el2:02 pm - 05/10/2021

Este articulo del gran Alberto Ferrari no tiene desperdicio:

https://www.sqlbi.com/blog/alberto/2021/01/22/on-how-to-ask-a-technical-question-if-you-really-want-an-answer/

Eia Publicado el1:38 pm - 16/11/2021

me ha gustado tu explicacion pero yo lo tengo mas dificil

tengo 32000 categorias que tengo que resumir en 200

por ejemplo la 1200245,1200246 y 1200245 tienen que ser sustitudas por la 726
se puede buscar la cadena de reemplazo?

se podria hacer tambien con algun tipo de tabla por ejemplo si meto en una columna las descripciones y sus numeros de categoria
y en el otro sus descripciones y numero de categoria que de alguna forma sustituyera los numeros de la primera por los de la segunda

espero haberme expresado bien

un saludo

Deja una respuesta