Forum Discussion
(M code)How to unpivot sepcial columns from independent Excel file which in a folder then summary it
There have many many Excel files(same structure) in a folder, I would like extract special columns(not fixed) in ervery Excel file, then unpivot the data base on the specail columns, and finally summarize the unpivot data to a summary file.
If user input the value(refer blue circle) in the "stage" column, it also must input "Category" and "Pattern"(refer red circle):
If user input none in the "stage" column(refer blue circle), the "Category" and "Pattern" also is none(refer red circle):
The source file: INPUT
Finally I want to get summary file: OUTPUT
How can I get the final Output file by M code? Much appreciated if you have any idea about the case!
Hi QZ ,
You can accomplish this by creating a Power Query function to process each Excel file and then applying that function across all files located in a specific folder. The process involves handling the unique two-row header structure and extracting the "Category" and "Pattern" metadata from each file before unpivoting the data into a summarized format.
Here is the complete M code to achieve this. You can paste this solution directly into the Advanced Editor of a blank query in either Excel or Power BI.
let // 1. Point to the folder containing your Excel files Source = Folder.Files("C:\YOUR\FOLDER\PATH"), // 2. Filter for Excel files only (optional but recommended) FilterExcelFiles = Table.SelectRows(Source, each Text.EndsWith([Name], ".xlsx") or Text.EndsWith([Name], ".xls")), // 3. Define the function to transform each file TransformFile = (binaryContent as binary) => let // Load the workbook and navigate to the first sheet Source = Excel.Workbook(binaryContent, null, true), Sheet1 = Source{[Item="Sheet1",Kind="Sheet"]}[Data], // Extract Category and Pattern from their specific cells // Note: {4} is row 5, {Column9} is column I; {Column15} is column O. Adjust if your layout is different. CategoryValue = try Sheet1{4}[Column9] otherwise null, PatternValue = try Sheet1{4}[Column15] otherwise null, // Prepare the main data table (skip top rows to get to the headers) DataTable = Table.Skip(Sheet1, 6), // Handle the two-level headers by transposing, filling, merging, and transposing back Transposed = Table.Transpose(DataTable), FilledDown = Table.FillDown(Transposed, {"Column1"}), MergedHeaders = Table.CombineColumns(Table.TransformColumnTypes(FilledDown, {{"Column2", type text}}, "en-US"),{"Column1", "Column2"},Combiner.CombineTextByDelimiter(" ", QuoteStyle.None),"MergedHeaders"), TransposedBack = Table.Transpose(MergedHeaders), // Promote the newly created first row to be the headers PromotedHeaders = Table.PromoteHeaders(TransposedBack, [PromoteAllScalars=true]), // Unpivot the stage columns, keeping the identifier columns UnpivotedData = Table.UnpivotOtherColumns(PromotedHeaders, {"Checker", "Machine no.", "S/C", "FB"}, "Stage", "Value"), // Filter out any rows where the value is null (i.e., no data was entered) FilteredRows = Table.SelectRows(UnpivotedData, each [Value] <> null), // Add the extracted Category and Pattern as new columns AddCategory = Table.AddColumn(FilteredRows, "Category", each CategoryValue), AddPattern = Table.AddColumn(AddCategory, "Pattern", each PatternValue) in AddPattern, // 4. Invoke the custom function on each file's content InvokeCustomFunction = Table.AddColumn(FilterExcelFiles, "Transform File", each TransformFile([Content])), // 5. Remove other columns, keeping only the transformed data RemoveOtherColumns = Table.SelectColumns(InvokeCustomFunction, {"Transform File"}), // 6. Expand the table column to get the final result ExpandedData = Table.ExpandTableColumn(RemoveOtherColumns, "Transform File", {"Checker", "Machine no.", "S/C", "FB", "Stage", "Value", "Category", "Pattern"}), // 7. Reorder columns to match the desired output ReorderedColumns = Table.ReorderColumns(ExpandedData,{"Checker", "Machine no.", "S/C", "FB", "Category", "Pattern", "Stage", "Value"}), // 8. Set the correct data types for the final columns ChangedType = Table.TransformColumnTypes(ReorderedColumns,{{"Checker", type text}, {"Machine no.", type text}, {"S/C", type text}, {"FB", Int64.type}, {"Category", type text}, {"Pattern", type text}, {"Stage", type text}, {"Value", Int64.type}}) in ChangedTypeTo use this code, first open Power Query by getting data from a folder (Data > Get Data > From File > From Folder in Excel). Point it to the folder containing your source files and click Transform Data. In the Power Query Editor, open the Advanced Editor from the Home tab. Delete any existing text and paste in the M code provided. The most important step is to update the folder path on the third line of the code to match your folder's location. After pasting and updating the path, click Done, and Power Query will process all the files and display the final summary table.
The code works by first using the Folder.Files function to get a list of all files. The core logic is contained within a custom function named TransformFile, which is designed to process one file at a time. Inside this function, it extracts the Category and Pattern values from their specific cell locations. It then cleverly handles the two-level column headers by transposing the table, filling down the stage names, merging the header rows into one, and transposing back. Following this, the Table.UnpivotOtherColumns function converts the wide stage columns into a long format. Finally, the extracted Category and Pattern are added as new columns to the resulting data. The main query then applies this function to every file, combines the results into a single table, and performs final cleanup like reordering columns and setting data types.
Best regards,
Great✊, your reply is very helpful for me, I'm researching the code, I'll paste the code once accomplish it.
7 Replies
- Omid_Motamedise
Super User
Hi
See the following video of mine
It will help you
- DataNinja777
Super User
Hi QZ ,
You can accomplish this by creating a Power Query function to process each Excel file and then applying that function across all files located in a specific folder. The process involves handling the unique two-row header structure and extracting the "Category" and "Pattern" metadata from each file before unpivoting the data into a summarized format.
Here is the complete M code to achieve this. You can paste this solution directly into the Advanced Editor of a blank query in either Excel or Power BI.
let // 1. Point to the folder containing your Excel files Source = Folder.Files("C:\YOUR\FOLDER\PATH"), // 2. Filter for Excel files only (optional but recommended) FilterExcelFiles = Table.SelectRows(Source, each Text.EndsWith([Name], ".xlsx") or Text.EndsWith([Name], ".xls")), // 3. Define the function to transform each file TransformFile = (binaryContent as binary) => let // Load the workbook and navigate to the first sheet Source = Excel.Workbook(binaryContent, null, true), Sheet1 = Source{[Item="Sheet1",Kind="Sheet"]}[Data], // Extract Category and Pattern from their specific cells // Note: {4} is row 5, {Column9} is column I; {Column15} is column O. Adjust if your layout is different. CategoryValue = try Sheet1{4}[Column9] otherwise null, PatternValue = try Sheet1{4}[Column15] otherwise null, // Prepare the main data table (skip top rows to get to the headers) DataTable = Table.Skip(Sheet1, 6), // Handle the two-level headers by transposing, filling, merging, and transposing back Transposed = Table.Transpose(DataTable), FilledDown = Table.FillDown(Transposed, {"Column1"}), MergedHeaders = Table.CombineColumns(Table.TransformColumnTypes(FilledDown, {{"Column2", type text}}, "en-US"),{"Column1", "Column2"},Combiner.CombineTextByDelimiter(" ", QuoteStyle.None),"MergedHeaders"), TransposedBack = Table.Transpose(MergedHeaders), // Promote the newly created first row to be the headers PromotedHeaders = Table.PromoteHeaders(TransposedBack, [PromoteAllScalars=true]), // Unpivot the stage columns, keeping the identifier columns UnpivotedData = Table.UnpivotOtherColumns(PromotedHeaders, {"Checker", "Machine no.", "S/C", "FB"}, "Stage", "Value"), // Filter out any rows where the value is null (i.e., no data was entered) FilteredRows = Table.SelectRows(UnpivotedData, each [Value] <> null), // Add the extracted Category and Pattern as new columns AddCategory = Table.AddColumn(FilteredRows, "Category", each CategoryValue), AddPattern = Table.AddColumn(AddCategory, "Pattern", each PatternValue) in AddPattern, // 4. Invoke the custom function on each file's content InvokeCustomFunction = Table.AddColumn(FilterExcelFiles, "Transform File", each TransformFile([Content])), // 5. Remove other columns, keeping only the transformed data RemoveOtherColumns = Table.SelectColumns(InvokeCustomFunction, {"Transform File"}), // 6. Expand the table column to get the final result ExpandedData = Table.ExpandTableColumn(RemoveOtherColumns, "Transform File", {"Checker", "Machine no.", "S/C", "FB", "Stage", "Value", "Category", "Pattern"}), // 7. Reorder columns to match the desired output ReorderedColumns = Table.ReorderColumns(ExpandedData,{"Checker", "Machine no.", "S/C", "FB", "Category", "Pattern", "Stage", "Value"}), // 8. Set the correct data types for the final columns ChangedType = Table.TransformColumnTypes(ReorderedColumns,{{"Checker", type text}, {"Machine no.", type text}, {"S/C", type text}, {"FB", Int64.type}, {"Category", type text}, {"Pattern", type text}, {"Stage", type text}, {"Value", Int64.type}}) in ChangedTypeTo use this code, first open Power Query by getting data from a folder (Data > Get Data > From File > From Folder in Excel). Point it to the folder containing your source files and click Transform Data. In the Power Query Editor, open the Advanced Editor from the Home tab. Delete any existing text and paste in the M code provided. The most important step is to update the folder path on the third line of the code to match your folder's location. After pasting and updating the path, click Done, and Power Query will process all the files and display the final summary table.
The code works by first using the Folder.Files function to get a list of all files. The core logic is contained within a custom function named TransformFile, which is designed to process one file at a time. Inside this function, it extracts the Category and Pattern values from their specific cell locations. It then cleverly handles the two-level column headers by transposing the table, filling down the stage names, merging the header rows into one, and transposing back. Following this, the Table.UnpivotOtherColumns function converts the wide stage columns into a long format. Finally, the extracted Category and Pattern are added as new columns to the resulting data. The main query then applies this function to every file, combines the results into a single table, and performs final cleanup like reordering columns and setting data types.
Best regards,
- QZ
Helper I
Great✊, your reply is very helpful for me, I'm researching the code, I'll paste the code once accomplish it.
- v-saisrao-msft
Community Support
Hi QZ,
Have you had a chance to review the solution we shared by DataNinja777 ? If the issue persists, feel free to reply so we can help further.
Thank you.
- v-saisrao-msft
Community Support
Hi QZ,
Checking in to see if your issue has been resolved. let us know if you still need any assistance.
Thank you.
- v-saisrao-msft
Community Support
Hi QZ,
We haven’t heard back from you in a while regarding your issue. let us know if your issue has been resolved or if you still require support.
Thank you.
- QZ
Helper I
DataNinja777 thank u very much! 🤝 Your answer is great, after made a small change to the code, it run smoothly.
let Source = Folder.Files("C:\Users\your name\Desktop\Input"), FilterExcelFiles = Table.SelectRows(Source, each Text.EndsWith([Name], ".xlsx") or Text.EndsWith([Name], ".xls")), // 3. Define the function to transform each file TransformFile = (binaryContent as binary) => let // Load the workbook and navigate to the first sheet Source = Excel.Workbook(binaryContent, null, true), Sheet1 = Source{[Item="Sheet1",Kind="Sheet"]}[Data], Removed Top Rows = Table.Skip(Sheet1,1), Removed Speical Rows = Table.RemoveRows(Removed Top Rows,1,1), Removed Columns1 = Table.RemoveColumns(Removed Speical Rows,{"Column3", "Column50", "Column51", "Column52"}), Custom define5 = Record.FieldValues(Removed Columns1{0}), Custom define6 = List.Transform(Custom define5, each if _ = null then "" else _), Custom define7 = List.Transform(Custom define6, each Text.Combine(List.FirstN(List.Alternate(Text.SplitAny(_ ,"()"), 1, 1),2))), Custom define12 = List.Transform(Custom define7, each if _ <> "" then _ else null), Custom define8 = Table.ColumnNames(Removed Columns1), Custom define9 = List.Transform(Custom define8, each _ & " ="), Custom define10 = List.Zip({Custom define9,Custom define12}), Custom define11 = List.Transform(Custom define10, each Text.Combine(_," ")), Custom define13 = List.Transform(Custom define11, each _ & ","), Custom define14 = Record.FromList(Custom define12,Custom define8), Custom define16 = Table.InsertRows(Removed Columns1,1,{Custom define14}), DataTable = Table.Skip(Custom define16, 1), Transposed = Table.Transpose(DataTable), FilledDown = Table.FillDown(Transposed, {"Column1"}), MergedHeaders = Table.CombineColumns(Table.TransformColumnTypes(FilledDown, {{"Column2", type text}}, "en-US"),{"Column1", "Column2"},Combiner.CombineTextByDelimiter("", QuoteStyle.None),"MergedHeaders"), TransposedBack = Table.Transpose(MergedHeaders), PromotedHeaders = Table.PromoteHeaders(TransposedBack, [PromoteAllScalars=true]), UnpivotedData = Table.UnpivotOtherColumns(PromotedHeaders, {"Checker", "Machine no.", "FB"}, "Stage", "Value"), Split Column by Delimiter = Table.SplitColumn(UnpivotedData, "Stage", Splitter.SplitTextByDelimiter("=", QuoteStyle.Csv), {"Stage.1", "Stage.2"}), Removed Columns = Table.RemoveColumns(Split Column by Delimiter,{"Stage.2"}), Custom define1 = Table.TransformColumns(Removed Columns, {{"Stage.1", each Text.RemoveRange(_, Text.Length(_) - 1, 1)}}), Renamed Columns = Table.RenameColumns(Custom define1,{{"Stage.1", "Stage"}}) in Renamed Columns, // 4. Invoke the custom function on each file's content InvokeCustomFunction = Table.AddColumn(FilterExcelFiles, "Transform File", each TransformFile([Content])), // 5. Remove other columns, keeping only the transformed data RemoveOtherColumns = Table.SelectColumns(InvokeCustomFunction, {"Transform File"}), // 6. Expand the table column to get the final result ExpandedData = Table.ExpandTableColumn(RemoveOtherColumns, "Transform File", {"Checker", "Machine no.", "FB", "Stage", "Value"}), // 7. Reorder columns to match the desired output ReorderedColumns = Table.ReorderColumns(ExpandedData,{"Checker", "Machine no.", "FB", "Stage", "Value"}), ChangedType = Table.TransformColumnTypes(ReorderedColumns,{{"Checker", type text}, {"Machine no.", type text}, {"FB", type text}, {"Stage", type text}, {"Value", Int64.Type}}) in ChangedType