Expansión de varias tablas de datos con nombres de columna desconocidos

Un usuario Pregunto ✅

usarazebra

Estoy creando una consulta que el usuario puede señalar fácilmente a una fuente alternativa sin que se interrumpa la consulta. Todas las tablas de origen están altamente estandarizadas, EXCEPTO los encabezados de las columnas (imagínense).

El abastecimiento dinámico funciona perfectamente. Este código siempre trae esta tabla exacta:

Fuente = Web.Página(Web.Contents(GetValue(«Primary_Table»))),
#»Filas filtradas» = Table.SelectRows(Source, each ([Caption] = nulo)),

El código generado automáticamente para expandir las dos tablas en la columna «Datos» usa nombres estáticos de los encabezados de columna de las subtablas:

#»Datos ampliados» = Table.ExpandTableColumn(#»Filas filtradas», «Datos», {«El año fiscal es enero-diciembre. Todos los valores en millones de USD.», «31 de diciembre de 2017», «30 de septiembre de 2017 «, «30 de junio de 2017», «31 de marzo de 2017», «31 de diciembre de 2016», «Tendencia de 5 trimestres», «Todos los valores en millones de USD».}),

EL PROBLEMA

Estoy tratando de hacer que mi código sea genérico, por lo que funcionará incluso cuando los encabezados de las subtablas cambien (y lo hacen). Creo que necesito una función para enumerar todos los encabezados de columna en esas dos tablas, así:

#»Datos ampliados» = Table.ExpandTableColumn(#»Filas filtradas», «Datos», List.Union(#»Filas filtradas»[Data])),

Ese código me da un error: «No podemos convertir un valor de tipo Tabla a tipo Lista»

Intenté agregar {} alrededor del [Data] referencia al final de la línea:

#»Datos ampliados» = Table.ExpandTableColumn(#»Filas filtradas», «Datos», List.Union(#»Filas filtradas»[Data])),

Lo que da el error: «Hay un identificador desconocido. ¿Utilizó el [field] abreviatura de _[field] fuera de una expresión ‘each’?»

¿Cómo hago para que este código expanda correctamente ambas subtablas de una manera que funcione incluso si los encabezados cambian?

ImkeF

En respuesta a greg_deckler

Cierto 🙂

Su sintaxis solo funcionaría si hiciera referencia a una columna que contiene los nombres de columna que ya se encuentran aquí, por ejemplo: https://www.mrexcel.com/forum/power-bi/952568-power-query-expand-all-columns. html

Pero en su caso, debe incluir la función Table.ColumnNames para recuperar primero los nombres de las columnas. Si desea incluirlo en un solo paso, podría verse así:

#"Expanded Data" = Table.ExpandTableColumn(#"Filtered Rows", "Data", List.Union(List.Transform(#"Filtered Rows"[Data]), each Table.ColumnNames(_)))

greg_deckler

He visto a @ImkeF responder problemas similares a este.

ImkeF

En respuesta a greg_deckler

Cierto 🙂

Su sintaxis solo funcionaría si hiciera referencia a una columna que contiene los nombres de columna que ya se encuentran aquí, por ejemplo: https://www.mrexcel.com/forum/power-bi/952568-power-query-expand-all-columns. html

Pero en su caso, debe incluir la función Table.ColumnNames para recuperar primero los nombres de las columnas. Si desea incluirlo en un solo paso, podría verse así:

#"Expanded Data" = Table.ExpandTableColumn(#"Filtered Rows", "Data", List.Union(List.Transform(#"Filtered Rows"[Data]), each Table.ColumnNames(_)))

usarazebra

En respuesta a ImkeF

¡Gracias por tu ayuda! Tuve que mover uno «)» por lo que el código ahora dice:

#"Expanded Data" = Table.ExpandTableColumn(#"Filtered Rows", "Data", List.Union(List.Transform(#"Filtered Rows"[Data], each Table.ColumnNames(_))))

Pregunta: Dijiste «Si quieres incluirlo en un solo paso…» ¿Tienes alguna sugerencia sobre una mejor manera de hacerlo, tal vez en varios pasos?

Anónimo

En respuesta a usarazebra

Gracias por esta solución y funciona perfectamente bien si usamos la obtención de datos de Excel, pero si obtenemos datos de la carpeta, entonces esto funciona demasiado lento. Tengo una carpeta con 1 excel (solo para probar guardé 1 pero habrá muchos archivos) y cuando apliqué este enfoque, fue demasiado lento cuando revisé la barra de estado y luego descubrí que estaba cargando más de 500 Mb de datos donde como el tamaño de mi archivo es de solo 1Mb. ¿Puede ayudarme a resolver esto (sé que podemos usar Table.Combine para lograrlo, pero eso no sirve para el propósito).

ImkeF

En respuesta a Anónimo

Hola @Anónimo,

No estoy seguro de poder seguir lo que estás describiendo aquí. Por favor, publique su código M para que pueda seguirlo.

Anónimo

En respuesta a ImkeF

El siguiente código funciona bien si cargo datos de Excel, es decir, selecciono Excel Data.xlsx

let
    Source = Excel.Workbook(File.Contents(""E:ProjectTestFilesData.xlsx"), null, true),
    #"Added Custom" = Table.AddColumn(Source, "PromoteHeader", each Table.PromoteHeaders([Data])),
    #"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"Data"}),
    DistinctColumn = List.Union(List.Transform(Table.Column(#"Removed Columns",Table.ColumnNames(#"Removed Columns"){0}), each Table.ColumnNames(_))), 
ExpandTable =Table.ExpandTableColumn(#"Removed Columns","PromoteHeader",DistinctColumn,DistinctColumn)
in
ExpandTable

Pero es demasiado lento en la última línea si cargo datos de la carpeta (en la barra de estado muestra la carga de más de 500 Mb de datos donde solo tengo 1 archivo en la carpeta con un tamaño de 1 Mb. También intenté usar Table.Buffer pero también va lento.

let
    Source = Folder.Files("E:ProjectTestFiles"),
    Step1 = Table.SelectColumns(Source,{"Content"}),
    Step2 = Table.AddColumn(Step1, "Custom", each Excel.Workbook([Content])),
    Step3 = Table.SelectColumns(Step2, {"Custom"}),
    Step4 = Table.ExpandTableColumn(Step3, "Custom", {"Name", "Data"}, {"Name", "Data"}),
    Step5 = Table.RemoveColumns(Step5 ,{"Name"}),
    Step6  = Table.AddColumn(Step6, "PromoteHeader", each Table.PromoteHeaders([Data])),
    Step7 = Table.SelectColumns(Step6,{"PromoteHeader"}),
    DistinctColumn = List.Union(List.Transform(Table.Column(Step7,Table.ColumnNames(Step7){0}), each Table.ColumnNames(_))),
    Step8 =Table.ExpandTableColumn(Step7,"PromoteHeader",DistinctColumn,DistinctColumn)
in
Step8

ImkeF

En respuesta a Anónimo

Hola @Anónimo,

su código no funciona para mí. Verifique si ha agregado o eliminado algunos pasos aquí antes de pegarlos en el hilo.

¿Qué estás intentando lograr?:

  1. Recupere dinámicamente los nombres del primer archivo y aplíquelo a todos los archivos de la carpeta o
  2. Recupere dinámicamente los nombres de TODOS los archivos en la carpeta y agregue todas las tablas (con los respectivos valores nulos para las columnas que no están presentes en todas las tablas)

Anónimo

En respuesta a ImkeF

Hola @ImkeF

Tengo una carpeta con varios archivos .xls con la misma estructura, cambiará en el futuro. Estoy tratando de agregar todo como un solo archivo y no necesito todas las columnas. Tengo alrededor de 40 columnas y, según el negocio, solo necesitamos 20 columnas. Entonces me referí a su método de expandir la columna dinámicamente. El siguiente código funciona pero es demasiado lento.

let
    Source = Folder.Files("E:ProjectTestFiles"),
    Step1 = Table.SelectColumns(Source,{"Content"}),
    Step2 = Table.AddColumn(Step1, "Custom", each Excel.Workbook([Content])),
    Step3 = Table.SelectColumns(Step2, {"Custom"}),
    Step4 = Table.ExpandTableColumn(Step3, "Custom", {"Name", "Data"}, {"Name", "Data"}),
    Step5 = Table.RemoveColumns(Step4 ,{"Name"}),
    Step6  = Table.AddColumn(Step5, "PromoteHeader", each Table.PromoteHeaders([Data])),
    Step7 = Table.SelectColumns(Step6,{"PromoteHeader"}),
    DistinctColumn = List.Union(List.Transform(Table.Column(Step7,Table.ColumnNames(Step7){0}), each Table.ColumnNames(_))),
    ExpandTable = Table.ExpandTableColumn(Step7,"PromoteHeader",DistinctColumn,DistinctColumn)
in
    ExpandTable

Para la prueba, solo tenía 1 archivo .xls de 1.5Mb en la carpeta, pero era demasiado lento y en la barra de estado mostraba que cargaba más de 500Mb (no tenía ni idea de cómo). Entonces, nuevamente intenté usar un solo archivo de Excel con el siguiente código y funcionó perfectamente bien.

let
    Source = Excel.Workbook(File.Contents("E:ProjectTestFilesData.xls"), null, true),
    #"Added Custom" = Table.AddColumn(Source, "PromoteHeader", each Table.PromoteHeaders([Data])),
    #"Removed Columns" = Table.SelectColumns(#"Added Custom",{"PromoteHeader"}),
    DistinctColumn = List.Union(List.Transform(Table.Column(#"Removed Columns",Table.ColumnNames(#"Removed Columns"){0}), each Table.ColumnNames(_))), 
    ExpandTable =Table.ExpandTableColumn(#"Removed Columns","PromoteHeader",DistinctColumn,DistinctColumn)
in
    ExpandTable

Ahora mi pregunta es: 1. ¿Por qué es demasiado lento para el primer código? me estoy perdiendo cualquier cosa.

2. ¿Cómo se puede arreglar?

Espero que la explicación anterior te dé una idea de lo que estoy tratando de lograr.

ImkeF

En respuesta a Anónimo

Hola @Anónimo,

Tengo algunas preguntas para ti:

1) ¿Por qué ignoras las preguntas de mi última publicación que me ayudarían a resolver tu problema?

2) ¿Por qué finges que tus primeros códigos funcionaron si no pudieron? Perdí mi tiempo con tu código defectuoso y ahora ni siquiera te molestas en disculparte por eso. He resaltado las correcciones que has hecho a continuación:

faulty code:
let
    Source = Excel.Workbook(File.Contents(""E:ProjectTestFilesData.xlsx"), null, true),
    #"Added Custom" = Table.AddColumn(Source, "PromoteHeader", each Table.PromoteHeaders([Data])),
    #"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"Data"}),
    DistinctColumn = List.Union(List.Transform(Table.Column(#"Removed Columns",Table.ColumnNames(#"Removed Columns"){0}), each Table.ColumnNames(_))), 
    ExpandTable =Table.ExpandTableColumn(#"Removed Columns","PromoteHeader",DistinctColumn,DistinctColumn)
in
    ExpandTable 
	
correct code:	
let
    Source = Excel.Workbook(File.Contents("E:ProjectTestFilesData.xls"), null, true),
    #"Added Custom" = Table.AddColumn(Source, "PromoteHeader", each Table.PromoteHeaders([Data])),
    #"Removed Columns" = Table.SelectColumns(#"Added Custom",{"PromoteHeader"}),
    DistinctColumn = List.Union(List.Transform(Table.Column(#"Removed Columns",Table.ColumnNames(#"Removed Columns"){0}), each Table.ColumnNames(_))), 
    ExpandTable =Table.ExpandTableColumn(#"Removed Columns","PromoteHeader",DistinctColumn,DistinctColumn)
in
    ExpandTable	
faulty code:
let
    Source = Folder.Files("E:ProjectTestFiles"),
    Step1 = Table.SelectColumns(Source,{"Content"}),
    Step2 = Table.AddColumn(Step1, "Custom", each Excel.Workbook([Content])),
    Step3 = Table.SelectColumns(Step2, {"Custom"}),
    Step4 = Table.ExpandTableColumn(Step3, "Custom", {"Name", "Data"}, {"Name", "Data"}),
    Step5 = Table.RemoveColumns(Step5 ,{"Name"}),
    Step6  = Table.AddColumn(Step6, "PromoteHeader", each Table.PromoteHeaders([Data])),
    Step7 = Table.SelectColumns(Step6,{"PromoteHeader"}),
    DistinctColumn = List.Union(List.Transform(Table.Column(Step7,Table.ColumnNames(Step7){0}), each Table.ColumnNames(_))),
    Step8 =Table.ExpandTableColumn(Step7,"PromoteHeader",DistinctColumn,DistinctColumn)
in
    Step8


correct code:
let
    Source = Folder.Files("E:ProjectTestFiles"),
    Step1 = Table.SelectColumns(Source,{"Content"}),
    Step2 = Table.AddColumn(Step1, "Custom", each Excel.Workbook([Content])),
    Step3 = Table.SelectColumns(Step2, {"Custom"}),
    Step4 = Table.ExpandTableColumn(Step3, "Custom", {"Name", "Data"}, {"Name", "Data"}),
    Step5 = Table.RemoveColumns(Step4 ,{"Name"}),
    Step6  = Table.AddColumn(Step5, "PromoteHeader", each Table.PromoteHeaders([Data])),
    Step7 = Table.SelectColumns(Step6,{"PromoteHeader"}),
    DistinctColumn = List.Union(List.Transform(Table.Column(Step7,Table.ColumnNames(Step7){0}), each Table.ColumnNames(_))),
    ExpandTable = Table.ExpandTableColumn(Step7,"PromoteHeader",DistinctColumn,DistinctColumn)
in
    ExpandTable	

?

Anónimo

En respuesta a ImkeF

Hola @ImkeF

Realmente lamento el error y no resalté el cambio en lugar de colocar el nuevo código y provocar la pérdida de su valioso tiempo. Primero publiqué con un sistema diferente, así que tuve que escribir el código manualmente al ver el código y es posible que lo pasé por alto en algunos puntos y, después de enviarlo, mostró un error y tuve que volver a escribir la publicación completa y causó un código incorrecto. Este es mi primer intento de publicar en el foro y lamento mucho mi error en el código y su tiempo también. Tendré mucho cuidado al publicar el código nuevamente.

ImkeF

En respuesta a Anónimo

Gracias @Anónimo, muy apreciado.

Puede intentar almacenar en búfer la lista con los nombres de columna de esta manera:

 DistinctColumn = List.Buffer(List.Union(List.Transform(Table.Column(Step7,Table.ColumnNames(Step7){0}), each Table.ColumnNames(_))))

Anónimo

En respuesta a ImkeF

Hola @ImkeF

Resolvió mi problema que usted por su orientación. 🙂 , ¿solo quiere entender qué hizo realmente este código? ¿Obligó a hacer el cálculo en la columna Distinct?

ImkeF

En respuesta a Anónimo

Hola @Anónimo,

eso es bueno escuchar 😉

El almacenamiento en búfer evitará que la misma expresión se evalúe innecesariamente varias veces. A veces funciona ya veces no, por lo que siempre vale la pena probarlo.

ImkeF

En respuesta a usarazebra

No, no creo que otras soluciones sean mejores. podrías haberlo hecho como en el enlace que he mencionado y tal vez encontrar tu código más fácil de administrar. La evaluación de la consulta probablemente no cambiaría.

jeffweir

En respuesta a ImkeF

Hola @ImkeF. Hay un pequeño error tipográfico en su respuesta muy útil … ha cerrado prematuramente la función List.Transform con un corchete antes de cada palabra clave. Debería ser así:

#"Expanded Data" = Table.ExpandTableColumn(#"Filtered Rows", "Data", List.Union(List.Transform(#"Filtered Rows"[Data], each Table.ColumnNames(_))))

…y no así:

#"Expanded Data" = Table.ExpandTableColumn(#"Filtered Rows", "Data", List.Union(List.Transform(#"Filtered Rows"[Data]), each Table.ColumnNames(_))) 

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *