martes, 24 de noviembre de 2020

Power Query: Alternativas a BUSCARV aproximado

Probablemente un clásico de las relaciones entre tablas sea la búsqueda aproximada, entendiendo por tal la busqueda de un valor por cercania o pertenencia a un intervalo.
Veamos la imagen siguiente:
Power Query: Alternativas a BUSCARV aproximado
Digamos que vamos a replicar el comportamiento de la función BUSCARV en su forma aproximada (cuarto arumento como VERDADERO).
Se trata de identificar el descuento a aplicar de acuerdo al número de unidades vendidas...
De tal forma que si he vendido, por ejemplo, 74 unidades... según mi tabla de intervalo de unidades (Desde 60 hasta 89), le correspondería un descuento del 8%.

Por desgracia en Power Query no existe un tipo de combinación entre tablas que replique tal cual este tipo de relación... por lo que, como en tantas ocasiones, tendremos que ser imaginativos ;-)

Veremos tres maneras altenativas, cada una con sus ventajas e inconvenientes, pero siempre válidas.

Como siempre comenzaremos cargando las dos tablas al editor de Power Query... ya sabes, desde la ficha Datos > grupo Obtener y transformar > Desde Tabla o Rango, solo con conexión.
Importante, sobre la primera Tabla 'TblVENTAS' hemos añadido una Columna Índice desde 1
Power Query: Alternativas a BUSCARV aproximado

Y sobre la segunda tabla 'TblDCTOS' agregamos una Columna personalizada con un texto cualquiera... en mi caso 'salto'
Power Query: Alternativas a BUSCARV aproximado

Igual de importante es cambiar el nombre de la columna 'Desde' por el nombre 'Unidades' (el mismo nombre de la TblVENTAS para ese campo)!!.
Son columnas y cambios que en alguno de los métodos posteriores necesitaremos...

Primer método: Agregar una columna condicional
En el editor de consultas iremos al menú Agregar columna > grupo General > Columna condicional Desde la configuración identificaremos manualmente los diferentes intervalos
Power Query: Alternativas a BUSCARV aproximado

Se observa como hemos ido insertando condiciones simples con el operador 'menor que' para cada intervalo:
Desde Hasta % Descuento
0 14 1%
15 34 3%
35 59 5%
60 89 8%
90 10%
La fórmula añadida a la consulta, desde el asistente, ha sido:
if [Unidades] < 15 then 0.01 else if [Unidades] < 35 then 0.03 else if [Unidades] < 60 then 0.05 else if [Unidades] < 90 then 0.08 else 0.10
que verifica y se ajusta a los descuentos correspondientes...
Un método muy simple de aplicar, sin duda, pero con la limitació obvia que, ante futuros cambios, esto es, nuevos intervalos o variación en los porcentajes... deberemos entrar en la consulta y cambiar manualmente esta configuración.

Segundo método: Trabajar con ambas tablas sin combinar.
Este caso requiere de un uso intermedio del lenguaje M, ya que deberemos picar algo de código... dejando el uso de los asistentes para aspectos residuales... Nuestro código a insertar en una consulta en blanco será:
let
    AddTblVentas=TblVENTAS,
    AddTblDCTO=Table.AddColumn(AddTblVentas, "descuentos", each TblDCTO),
    
    ExpandeDescuentos = Table.ExpandTableColumn(AddTblDCTO, "descuentos", {"Unidades", "Hasta", "% Descuento", "Salto"}, {"Desde", "Hasta", "% Descuento", "Salto"}),

    Reemplazo = Table.ReplaceValue(ExpandeDescuentos,null,Record.Field(Table.Max(Table.SelectColumns(ExpandeDescuentos,"Unidades"),"Unidades"),"Unidades"),Replacer.ReplaceValue,{"Hasta"}),

    AddCondicional = Table.AddColumn(Reemplazo, "Descuentos", each if [Unidades]>=[Desde] and [Unidades]<=[Hasta] then [#"% Descuento"] else 0),
    #"Filtro<>0" = Table.SelectRows(AddCondicional, each [Descuentos] <> 0),
    Columnas_Quitadas = Table.RemoveColumns(#"Filtro<>0",{"Índice", "Desde", "Hasta", "Salto", "Descuentos"})
in
    Columnas_Quitadas

Power Query: Alternativas a BUSCARV aproximado

La esencia de este método es que al juntar en la misma consulta dos tablas (TblVENTAS y TblDCTO) se produce un listado de todas las posibles combinaciones entre los registros de ambas tablas:
Power Query: Alternativas a BUSCARV aproximado

Esto nos permite comparar, con una columna personalizada, con una condición comparativa entre columnas, determinar a qué intervalo pertenecen las unidades buscadas:
if [Unidades]>=[Unidades.1] and [Unidades]<=[Hasta] then [#"% Descuento"] else 0
obteniendo dato solo para el porcentaje buscado, y cero para los demás casos...
El siguiente paso de la consulta es claro, con un filtro sencillo, dejo fuera de la consulta esas filas con valor cero, esto es, aquellas filas que no han cruzado con ningún intervalo!.
Como apunte interesante, y para evitar errores al aplicar en anterior condicional, se reemplazó el valor 'null' del último intervalo de descuento (Desde 90 Hasta 'vacío') con el valor máximo de entre las unidades vendidas:
Reemplazo = Table.ReplaceValue(ExpandeDescuentos,null,Record.Field(Table.Max(Table.SelectColumns(ExpandeDescuentos,"Unidades"),"Unidades"),"Unidades"),Replacer.ReplaceValue,{"Hasta"})
Nos quedamos con el valor máximo (Tabla.Max) de la columna necesaria 'Unidades' (Table.SelecColumns), recuperando el dato con 'Record.Value'.
Lo interesante de este método es que está abierto a cualquier tipo de cambio en la tabla de descuentos... y como inconveniente, el tipo de unión empleada, que podrá generar fallos en la consulta cuando el número de filas en las tablas sea elevado.

Y vamos a por el tercer método: Anexando ambas tablas.
Muy interesante el empleo de esta herramienta 'Anexar consultas' en vez de lo que nos dice el sentido común 'Combinar consultas'.
Comenzaremos desde la consulta de la 'TblVENTAS' para Anexar consultas para crear una nueva, donde seleccionaremos para anexar la TblVENTAS y la TblDCTO con los cambios ya efectuadas al inicio del proceso!!.
Power Query: Alternativas a BUSCARV aproximado

Vemos que el resultado ha anexado, en el campo 'Unidades' en primer lugar los datos de TblVENTAS y a continuación los datos de TblDCTO; los correspondientes al campo 'Desde' que cambiamos de nombre por 'Unidades'.
El sentido del cambio era este... al llamarse ambos campos/columnas iguales, el anexado los une sobre la misma columna.
El resto de campos al no coincidir entre sí los anexa en columnas nuevas...
Power Query: Alternativas a BUSCARV aproximado

En el siguiente paso, muy sencillo, ordenaremos en Ascendente precisamente por la columna 'Unidades'; para seguidamente forzar sobre la columna del '% descuento' la acción de Rellenar Hacía abajo
Power Query: Alternativas a BUSCARV aproximado

Observa como al ordenar por 'Unidades' se han intercalado nuestros intervalos, partiendo de alguna manera nuestras filas entre esos valores... para finalmente rellenar con los porcentajes de descuentos a aplicar para todas esas unidades entre los intervalos necesarios.
Terminamos aplicando un Filtro sobre la columna 'Salto' para eliminar esas filas donde aparezca el texto 'salto' (recuerda que venían de la TblDCTO tratada)... esto es, quitamos las filas de las tablas no necesarias.
Ordenamos por la columna Índice para recuperar el orden original de los registros de ventas.
Y quitamos columnas no necesarias... para llegar a nuestra consulta final
Power Query: Alternativas a BUSCARV aproximado

El código generado:
let
    Origen = Table.Combine({TblVENTAS, TblDCTO}),
    #"Filas ordenadas" = Table.Sort(Origen,{{"Unidades", Order.Ascending}}),
    RellenarHaciaAbajo = Table.FillDown(#"Filas ordenadas",{"% Descuento"}),
    FiltroQuita_salto = Table.SelectRows(RellenarHaciaAbajo, each ([Salto] = null)),
    Ordena_Inicio = Table.Sort(FiltroQuita_salto,{{"Índice", Order.Ascending}}),
    ColumnasQuitadas = Table.RemoveColumns(Ordena_Inicio,{"Hasta", "Salto","Índice"})
in
    ColumnasQuitadas
Un último método sencillo, que no requiere de conocimientos específicos del lenguaje M, y que nos permite la flexibilidad que necesitamos ante modificaciones en nuestras tablas originales...

No hay comentarios:

Publicar un comentario

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