Días atrás expliqué una alternativa al clásico Table.NestedJoin (i.e., a la acción de Combinar consultas).
Hoy veremos una nueva posibilidad empleando otra función M importante: Table.SelectRows:
Table.SelectRows(table as table, condition as function) as table
Es una función conocida por todos, ya que es la que sirve para aplicar filtros sobre una tabla, es decir, muestra solo las filas de una tabla que cumplen las condiciones dadas...
Si bien, lo habitual es trabajar sobre columnas y filas de la misma tabla...
Y ahí reside lo interesante del artículo de hoy. Veremos como con esta función podremos obtener datos de terceras tablas!!
Partiremos de las cinco tablas fuentes siguientes, situadas en nuestro libro de trabajo: 'TblDATOS','TblREGION','TblDESCUENTOS','TblPRECIOS' y 'TblCOMISION':
Comenzaremos cargando las cinco tablas, solo como conexión, en nuestro editor de consultas de Power Query.
En un primer ejercicio, con el objetivo de comparar tiempos de ejecución, montaremos una consulta donde emplearemos la herramienta 'Combinar consultas' (por tanto: Table.NestedJoin).
Empezando desde la 'TblDATOS' iremos combinando y expandiendo los distintos campos necesarios... El código quedaría:
Puesto que solo he seguido la mecánica tantas veces vista en el blog, no me detengo en esta parte... (Para más detalle accede a la categoría de Power Query).
Lo importante viene ahora, donde empleando la función Table.SelectRows replicaremos esas relaciones entre distintas consultas o tablas!!.
En una nueva consulta en blanco escribiremos:
En esencia, la parte relevante es donde se emplea Table.SelectRows:
A pesar de estar trabajando sobre la TblDATOS, podemos referirnos a una tercera tabla ('TblPRECIOS') para recuperar aquellas filas donde se de la condición de que en su columna [Artículo] (OJO!, columna de la tabla TblPRECIOS!!) sea igual al dato 'a' (variable cargada previamente con el dato de la misma fila y la columna [Producto] de la tabla TblDATOS.
La información resultante la incorporamos en una nueva columna de la TblDATOS... lo que se consigue con la función Table.AddColumn:
De cada tabla resultante para cada fila, nos interesa recuperar el dato de la columna [Precio] y el primer y único valor de la fila 1 ([Precio]{0})
Si el cruce de información debe responder a un doble criterio, podemos añadirlo en el argumento de condición de Table.SelectRows:
La doble condición, en este caso, se aplica con un criterio lógico 'and':
each [Cod] = a and [Vendedor]=c
donde 'a' y 'c' son variables cargadas previamente con los valores de la TblDATOS de las columnas [Producto] y [Comercial].
Otro caso diferente es cuando queremos recuperar información de más de una columna....
Existen diferentes métodos (los más eficientes suelen ser trabajar con 'Records'), pero en este caso expondré uno distinto empleando concatenaciones (Table.CombineColumns) y divisiones de columnas (Table.SplitColumn).
Algo largo... pero fácil de entender.
Desde lo más 'profundo' de la fórmula hacia afuera...
Primero tenemos la selección de filas de la TblDESCUENTO que cumplen la condición de tener igual 'Comerciales' (con Table.SelectRows).
Segundo. Para poder concatenar las columnas deseadas, les cambiamos el tipo de datos a text, con la función Table.TransformColumnTypes
Ese concatenado resultante de las columnas 'Dirección' y 'Descuento' de la TblDESCUENTOS, lo agregamos en una nueva columna en la TblDATOS... usando Table.Addcolumns
Finalmente, aplicamos una división de esta columna recién agregada con Table.SplitColumn
Algo 'retorcidillo'... pero interesante por el uso de distintas funciones M frecuentes en otros contextos...
Desde luego el resultado es idéntico a la primera consulta creada con la herramienta de Combinar consultas.
Algo muy importante que debemos tener presente al usar este sistema es la optimización y/o la agilidad y rapidez de la carga de datos...
Este sistema es sustancialmente más lento que el clásico de 'combinar consultas'!!... pero por contra ofrece un infinito mundo de posibilidades para cruzar distintas tablas, y no únicamente el básico 1-1, 2-2,..., n-n de Table.NestedJoin.
Veamos un ejemplo al respecto...
Supongamos una nueva tabla con unas tarifas determinadas por un rango de fechas (Desde - Hasta) por cada comercial y que únicamente deben aplicar a ES, IT y FR:
Como siempre cargaremos esta nueva tabla ('TblTARIFAS') solo como conexión. Y a continuación desde una consulta en blanco escribiremos:
Tras definir y cargar las variable 'f' y 'c' con los datos de la 'TblDATOS', procedemos a aplicar la comparativa (mayor o igual que, menor o igual que) con las filas de la TblTARIFAS dentro del contexto de la función Table.SelectRows (como hemos visto más arriba...).
Condiciones solo aplicadas cuando se cumpla las condiciones lógicas del 'or' indicada con un if... then... else....
Obteniendo:
Todas estas opciones y posibles condiciones a incorporar a nuestras consultas resultan muy cómodas de aplicar con este método... y no tanto con otros alternativos, por lo que nuevamente debemos sopesar pros y contras en cada caso particular antes de decidirnos por un método a aplicar ;-)
Hoy veremos una nueva posibilidad empleando otra función M importante: Table.SelectRows:
Table.SelectRows(table as table, condition as function) as table
Es una función conocida por todos, ya que es la que sirve para aplicar filtros sobre una tabla, es decir, muestra solo las filas de una tabla que cumplen las condiciones dadas...
Si bien, lo habitual es trabajar sobre columnas y filas de la misma tabla...
Y ahí reside lo interesante del artículo de hoy. Veremos como con esta función podremos obtener datos de terceras tablas!!
Partiremos de las cinco tablas fuentes siguientes, situadas en nuestro libro de trabajo: 'TblDATOS','TblREGION','TblDESCUENTOS','TblPRECIOS' y 'TblCOMISION':
Comenzaremos cargando las cinco tablas, solo como conexión, en nuestro editor de consultas de Power Query.
En un primer ejercicio, con el objetivo de comparar tiempos de ejecución, montaremos una consulta donde emplearemos la herramienta 'Combinar consultas' (por tanto: Table.NestedJoin).
Empezando desde la 'TblDATOS' iremos combinando y expandiendo los distintos campos necesarios... El código quedaría:
let Origen = Excel.CurrentWorkbook(){[Name="TblDATOS"]}[Content], Tipo_cambiado = Table.TransformColumnTypes(Origen,{{"Fecha", type datetime}, {"País", type text}, {"Comercial", type text}, {"Producto", type text}, {"Unidades", Int64.Type}}), Consultas_combinadas = Table.NestedJoin(Tipo_cambiado, {"País"}, TblREGION, {"Country"}, "TblREGION", JoinKind.LeftOuter), Se_expandió_TblREGION = Table.ExpandTableColumn(Consultas_combinadas, "TblREGION", {"Region", "UE/No UE"}, {"Region", "UE/No UE"}), Consultas_combinadas1 = Table.NestedJoin(Se_expandió_TblREGION, {"Comercial"}, TblDESCUENTO, {"Comerciales"}, "TblDESCUENTO", JoinKind.LeftOuter), Se_expandió_TblDESCUENTO = Table.ExpandTableColumn(Consultas_combinadas1, "TblDESCUENTO", {"Dirección", "Descuento"}, {"Dirección", "Descuento"}), Consultas_combinadas2 = Table.NestedJoin(Se_expandió_TblDESCUENTO, {"Producto"}, TblPRECIOS, {"Artículo"}, "TblPRECIOS", JoinKind.LeftOuter), Se_expandió_TblPRECIOS = Table.ExpandTableColumn(Consultas_combinadas2, "TblPRECIOS", {"Precio"}, {"Precio"}), Consultas_combinadas3 = Table.NestedJoin(Se_expandió_TblPRECIOS, {"Producto", "Comercial"}, TblCOMISION, {"Cod", "Vendedor"}, "TblCOMISION", JoinKind.LeftOuter), Se_expandió_TblCOMISION = Table.ExpandTableColumn(Consultas_combinadas3, "TblCOMISION", {"Comisión"}, {"Comisión"}) in Se_expandió_TblCOMISION
Puesto que solo he seguido la mecánica tantas veces vista en el blog, no me detengo en esta parte... (Para más detalle accede a la categoría de Power Query).
Lo importante viene ahora, donde empleando la función Table.SelectRows replicaremos esas relaciones entre distintas consultas o tablas!!.
En una nueva consulta en blanco escribiremos:
let Origen = TblDATOS, //Agregamos una nueva columna con el Precio (de la TblPRECIOS) correspondiente //cuando coincidan los códigos de los productos ('Producto' = 'Artículo') AddCol_PRECIO= Table.AddColumn( Origen, "N_Precio", each let a=[Producto] in Table.SelectRows(TblPRECIOS, each [Artículo] = a )[Precio]{0}), //Dividimos una columna en dos. //Columna que hemos agregado con información de la TblREGION, tras verificar la coincidencia del País //Al necesitar recuperar dos columnas de REGION, //he realizado una concatenación (Table.CombineColumns) de la info de dos columnas AddCol_REGION= Table.SplitColumn( Table.AddColumn( AddCol_PRECIO, "N_Región", each let p=[País] in Table.CombineColumns( Table.SelectRows(TblREGION, each [Country] = p ), {"Region","UE_Y_N"},Combiner.CombineTextByDelimiter("|"),"Para_extraer")[Para_extraer]{0}), "N_Región", Splitter.SplitTextByDelimiter("|", QuoteStyle.Csv), {"Region", "UE_Y_N"} ), //idem al anterior pero para la TblDESCUENTOS AddCol_DCTO= Table.SplitColumn( Table.AddColumn( AddCol_REGION, "N_Comercial", each let c=[Comercial] in Table.CombineColumns(Table.TransformColumnTypes( Table.SelectRows(TblDESCUENTO, each [Comerciales] = c ), {"Descuento", type text}), {"Dirección","Descuento"},Combiner.CombineTextByDelimiter("|"),"Para_extraer")[Para_extraer]{0}), "N_Comercial", Splitter.SplitTextByDelimiter("|", QuoteStyle.Csv), {"Dirección","Descuento"} ), //Agregamos el dato de la 'comisión' desde la TblCOMISION cuando se de la doble coincidencia de Comrcial y Artículo AddCol_COMISION= Table.AddColumn( AddCol_DCTO, "N_Comision", each let a=[Producto], c=[Comercial] in Table.SelectRows(TblCOMISION, each [Cod] = a and [Vendedor]=c)[Comisión]{0}) in AddCol_COMISION
En esencia, la parte relevante es donde se emplea Table.SelectRows:
Table.SelectRows(TblPRECIOS, each [Artículo] = a )[Precio]{0}
A pesar de estar trabajando sobre la TblDATOS, podemos referirnos a una tercera tabla ('TblPRECIOS') para recuperar aquellas filas donde se de la condición de que en su columna [Artículo] (OJO!, columna de la tabla TblPRECIOS!!) sea igual al dato 'a' (variable cargada previamente con el dato de la misma fila y la columna [Producto] de la tabla TblDATOS.
La información resultante la incorporamos en una nueva columna de la TblDATOS... lo que se consigue con la función Table.AddColumn:
Table.AddColumn( Origen, "N_Precio", each let a=[Producto] in Table.SelectRows(TblPRECIOS, each [Artículo] = a )[Precio]{0})
De cada tabla resultante para cada fila, nos interesa recuperar el dato de la columna [Precio] y el primer y único valor de la fila 1 ([Precio]{0})
Si el cruce de información debe responder a un doble criterio, podemos añadirlo en el argumento de condición de Table.SelectRows:
Table.AddColumn( AddCol_DCTO, "N_Comision", each let a=[Producto], c=[Comercial] in Table.SelectRows(TblCOMISION, each [Cod] = a and [Vendedor]=c)[Comisión]{0})
La doble condición, en este caso, se aplica con un criterio lógico 'and':
each [Cod] = a and [Vendedor]=c
donde 'a' y 'c' son variables cargadas previamente con los valores de la TblDATOS de las columnas [Producto] y [Comercial].
Otro caso diferente es cuando queremos recuperar información de más de una columna....
Existen diferentes métodos (los más eficientes suelen ser trabajar con 'Records'), pero en este caso expondré uno distinto empleando concatenaciones (Table.CombineColumns) y divisiones de columnas (Table.SplitColumn).
Table.SplitColumn( Table.AddColumn( AddCol_REGION, "N_Comercial", each let c=[Comercial] in Table.CombineColumns(Table.TransformColumnTypes( Table.SelectRows(TblDESCUENTO, each [Comerciales] = c ), {"Descuento", type text}), {"Dirección","Descuento"},Combiner.CombineTextByDelimiter("|"),"Para_extraer")[Para_extraer]{0}), "N_Comercial", Splitter.SplitTextByDelimiter("|", QuoteStyle.Csv), {"Dirección","Descuento"} )
Algo largo... pero fácil de entender.
Desde lo más 'profundo' de la fórmula hacia afuera...
Primero tenemos la selección de filas de la TblDESCUENTO que cumplen la condición de tener igual 'Comerciales' (con Table.SelectRows).
Segundo. Para poder concatenar las columnas deseadas, les cambiamos el tipo de datos a text, con la función Table.TransformColumnTypes
Ese concatenado resultante de las columnas 'Dirección' y 'Descuento' de la TblDESCUENTOS, lo agregamos en una nueva columna en la TblDATOS... usando Table.Addcolumns
Finalmente, aplicamos una división de esta columna recién agregada con Table.SplitColumn
Algo 'retorcidillo'... pero interesante por el uso de distintas funciones M frecuentes en otros contextos...
Desde luego el resultado es idéntico a la primera consulta creada con la herramienta de Combinar consultas.
Algo muy importante que debemos tener presente al usar este sistema es la optimización y/o la agilidad y rapidez de la carga de datos...
Este sistema es sustancialmente más lento que el clásico de 'combinar consultas'!!... pero por contra ofrece un infinito mundo de posibilidades para cruzar distintas tablas, y no únicamente el básico 1-1, 2-2,..., n-n de Table.NestedJoin.
Veamos un ejemplo al respecto...
Supongamos una nueva tabla con unas tarifas determinadas por un rango de fechas (Desde - Hasta) por cada comercial y que únicamente deben aplicar a ES, IT y FR:
Como siempre cargaremos esta nueva tabla ('TblTARIFAS') solo como conexión. Y a continuación desde una consulta en blanco escribiremos:
let Origen = TblDATOS, AddCol_TARIFAS= Table.AddColumn( Origen, "N_Tarifa", each let f=[Fecha], c=[Comercial] in if ([País]="ES" or [País]="FR" or [País]="IT") then Table.SelectRows(TblTARIFAS, each ([Desde] <= f and [Hasta]>=f) and [Comercial]=c)[Tarifa]{0} else null) in AddCol_TARIFAS
Tras definir y cargar las variable 'f' y 'c' con los datos de la 'TblDATOS', procedemos a aplicar la comparativa (mayor o igual que, menor o igual que) con las filas de la TblTARIFAS dentro del contexto de la función Table.SelectRows (como hemos visto más arriba...).
Condiciones solo aplicadas cuando se cumpla las condiciones lógicas del 'or' indicada con un if... then... else....
Obteniendo:
Todas estas opciones y posibles condiciones a incorporar a nuestras consultas resultan muy cómodas de aplicar con este método... y no tanto con otros alternativos, por lo que nuevamente debemos sopesar pros y contras en cada caso particular antes de decidirnos por un método a aplicar ;-)
No hay comentarios:
Publicar un comentario
Nota: solo los miembros de este blog pueden publicar comentarios.