Power Query - how to use parameter in Table.SelectColumns - excel

I want to pass a text parameter to "Table.SelectColumns(#Tablename, parametername).
parametername value is literally:' "AB01", "AB02", "AB03" 'etc., these are column names which I want to be selected in other query. Column names are taken from an excel table and those are changing each time I use the file, it may be 1 column name, but it also may be 20 names to be selected in PQ.
parametername (taken from table t_Parameters in excel):
Screen from PQ
let
Source = Excel.CurrentWorkbook(){[Name="t_Parameters"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Parameter Name", type text}, {"Parameter Value", type text}}),
#"Filtered Rows" = Table.SelectRows(#"Changed Type", each ([Parameter Name] = "Other CoCd's")),
#"Removed Other Columns" = Table.SelectColumns(#"Filtered Rows",{"Parameter Value"}),
#"Parameter Value" = #"Removed Other Columns"{0}[Parameter Value]
in
#"Parameter Value"
Line of function which does not work in other query, looks like that:
= Table.SelectColumns(#"Changed Type1",{parametername})
Screen2 from PQ - ERROR
Error says that there are no columns with those names, but in fact there are:
Screen3 from PQ - columns
Can you please indicate what I do wrong?
I spend a lot of time trying to create some workaround, but with no success :( , I just want to have dynamic columns selection based on parameter from t_Parameters table, other columns should be removed/ not visible.

Related

Merging subsequent cell values only for same ids in excel

I have a requirement here in excel where I have to populate "Facility" column with Country and City names in a single cell for the distributed data in C and D columns but only for the same id.
I have attached the image for reference
Thanks for your time in advance
I tried CONCAT function and TEXTJOIN function but that didn't help
This can be accomplished using Power Query, available in Windows Excel 2010+ and Excel 365 (Windows or Mac)
To use Power Query
Select some cell in your Data Table
Data => Get&Transform => from Table/Range
When the PQ Editor opens: Home => Advanced Editor
Make note of the Table Name in Line 2
Paste the M Code below in place of what you see
Change the Table name in line 2 back to what was generated originally.
Read the comments and explore the Applied Steps to understand the algorithm
M Code
let
//Change next line to reflect actual data source
Source = Excel.CurrentWorkbook(){[Name="Table31"]}[Content],
//set data types for each column
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Id", Int64.Type}, {"Country", type text}, {"City", type text}}),
//Group by ID
#"Grouped Rows" = Table.Group(#"Changed Type", {"Id"}, {
//for each subgroup, group by Country
{"Facility", (t)=> let
grp=Table.Group(t,{"Country"},{
//Then combine all the cities in one text string
"Cities", (tc)=> "(" & Text.Combine(tc[City],",") & ")"}),
//Add index column to "number" the different country/cities combinations
#"Add Index" = Table.AddIndexColumn(grp, "Index",1),
#"Index to Text" = Table.TransformColumns(#"Add Index",{"Index", each Number.ToText(_,"0\. ")}),
//combine the separate subtable columns into one string
#"Combine Columns" = Table.CombineColumns(
#"Index to Text",{"Index","Country","Cities"},Combiner.CombineTextByDelimiter(""),"Facility"),
//combine the separate rows into a single row
#"Combine to One Row" = Text.Combine(#"Combine Columns"[Facility]," ")
in
#"Combine to One Row", type text},
{"All", each _, type table [Id=nullable number, Country=nullable text, City=nullable text]}}),
//Expand the Country and City columns
#"Expanded All" = Table.ExpandTableColumn(#"Grouped Rows", "All", {"Country", "City"})
in
#"Expanded All"

Scan worksheet for missing items per ID

I have a worksheet with IDs of people visiting on certain days.
Simple example.
I want to scan all IDs to check if they have missed a visit day. When visit day 1, 2, 3, 4 and 5 are obligated.
I can't add code to this database, because it is locked (it is a worksheet with confidential info).
I don't know where to start.
The following solution is using Power Query which is available in Excel 2010 Professional Plus and all later versions of Excel. My demonstration is using Excel 365.
Suppose you have two tables:
Table1 is called Tbl_Visitday which is the 2-Column table in your example;
Table2 is called Rng_Obligated which is a 1-Column table containing all obligated days.
Go to Data tab in your Excel ribbon, use From Table function to add both tables to the power query editor one by one. When you access the editor for the first time, make sure set up the Query Options as below to avoid loading every query to a new worksheet;
Once you have added both tables to the editor, make a duplicate of Tbl_Visitday in the Queries section on the left hand side as shown below:
Let's work on Rng_Obligated first, highlight the column, use Transpose function under the Transform tab to transpose the data from rows to columns, then use Merge Columns function to merge all columns by delimiter semicolon ;, then you should have something like the following:
Let's move to Tbl_Obligated(2), remove the Visitday column, remove duplicates within the ID column and sort it ascending, then you should have:
Use Append Queries function under the Home tab to append Rng_Obligated table to the current table, and then right click the Merged column header and choose Fill -> Up to quickly fill the merged column with the same string, then you should have something like follow:
Filtered the ID column to hide null, then use the Split Columns function under the Transform tab to split the Merged column by delimiter semicolon ;, and in the advanced options to choose to put the results into Rows as shown below:
Use Merge Queries function under the Home tab to merge Tbl_Visitday table with the current table by holding the Ctrl key and select the first and second column consecutively in each table as shown below:
Expand the newly merge column to show Visitday column only, add a custom column using this formula =[Merged]=[Visitday], then filter the Custom column to show FALSE results only, then you should have:
Change the format of the Merged column to Text, then use Group By function under the Transform tab to group the Merged column by ID as shown below, the result will be error which is expected:
Go back to the last step in the APPLIED STEPS section on the right hand side, go to the formula bar and replace this part of the formula List.Sum([Merged]) with Text.Combine([Merged],","), hit enter and you will notice the error have become a text string as shown below:
You can close and load the query which will be created as a connection if you have amended the query setting in the first step. You can click Queries & Connections under the Data tab and right click the query and choose to load it to a specific location in your workbook.
In your case, you will need to ask the owner of the shared workbook to unlock the workbook so you can use the power query editor and load the output. Alternatively you can copy and paste the data to a new workbook where you can execute the power query to obtain the result.
Power Query allows you to update your source tables and recalculate the output (once you choose to refresh the data) in the back-end normally in a few seconds. If you do not want the output to be refreshed, you can copy and paste the output to a new table so the results stay unchanged.
Here are the power query M Code for the two tables for your reference. Let me know if you have any questions. Cheers :)
Rng_Obligated
let
Source = Excel.CurrentWorkbook(){[Name="Rng_Obligated"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"obligated", Int64.Type}}),
#"Transposed Table" = Table.Transpose(#"Changed Type"),
#"Merged Columns" = Table.CombineColumns(Table.TransformColumnTypes(#"Transposed Table", {{"Column1", type text}, {"Column2", type text}, {"Column3", type text}, {"Column4", type text}, {"Column5", type text}, {"Column6", type text}, {"Column7", type text}}, "en-AU"),{"Column1", "Column2", "Column3", "Column4", "Column5", "Column6", "Column7"},Combiner.CombineTextByDelimiter(";", QuoteStyle.None),"Merged")
in
#"Merged Columns"
Tbl_Visitday(2)
let
Source = Excel.CurrentWorkbook(){[Name="Tbl_Visitday"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"ID", type text}, {"Visitday", type text}}),
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"Visitday"}),
#"Removed Duplicates" = Table.Distinct(#"Removed Columns"),
#"Sorted Rows" = Table.Sort(#"Removed Duplicates",{{"ID", Order.Ascending}}),
#"Appended Query" = Table.Combine({#"Sorted Rows", Rng_Obligated}),
#"Filled Up" = Table.FillUp(#"Appended Query",{"Merged"}),
#"Filtered Rows" = Table.SelectRows(#"Filled Up", each ([ID] <> null)),
#"Split Column by Delimiter" = Table.ExpandListColumn(Table.TransformColumns(#"Filtered Rows", {{"Merged", Splitter.SplitTextByDelimiter(";", QuoteStyle.Csv), let itemType = (type nullable text) meta [Serialized.Text = true] in type {itemType}}}), "Merged"),
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Merged", Int64.Type}}),
#"Merged Queries" = Table.NestedJoin(#"Changed Type1",{"ID", "Merged"},Tbl_Visitday,{"ID", "Visitday"},"Table6",JoinKind.LeftOuter),
#"Expanded Table6" = Table.ExpandTableColumn(#"Merged Queries", "Table6", {"Visitday"}, {"Visitday"}),
#"Added Custom" = Table.AddColumn(#"Expanded Table6", "Custom", each [Merged]=[Visitday]),
#"Filtered Rows1" = Table.SelectRows(#"Added Custom", each ([Custom] = false)),
#"Changed Type2" = Table.TransformColumnTypes(#"Filtered Rows1",{{"Merged", type text}}),
#"Grouped Rows" = Table.Group(#"Changed Type2", {"ID"}, {{"MissedDay", each Text.Combine([Merged],","), type text}})
in
#"Grouped Rows"

Is there a way to join multiple strings in value fields when pivoting?

I am trying to make a table more readable by making a report.
This table has 3 columns;
Staff
Task (Each staff could have 0-many tasks)
Status (Planned, Started, Finished)
The report would have Staff as the left most column, 3 status as column headings. The values should be task values and if there are many tasks it should be concatenated, say, with a carriage return.
I tried pivoting but it didn't work since the task values are texts. I tried Power Query and it displays errors for every cell where there are more than 1 task.
Is there a way to do this? ...without VBA please.
Thanks
I presume you know how to operate Power Query Editor so I will skip the part of how to add data to the editor.
In my solution, I used the following sample data stored in Table3.
Once added data the editor will automatically recognize all data as text.
My approach is to add a custom column to combine Staff and Status as below first:
Then I grouped the data by the custom column (Staff+Status) with some Advanced Coding. You can do a Group By first and then go to Advanced Editor to change the formula as below:
= Table.Group(#"Added Custom", {"Staff+Status"}, {{"Task", each Text.Combine([Task],"#(lf)"), type text}})
Which will give you the following look:
Then you can split the custom column back to Staff and Status separately:
Then you can pivot the Status column, set Task as the Values Column, and in the Advanced Options set Don't Aggregate as the Aggregate Value Function.
Then you pretty much finished here, and you can load the query to a worksheet which may look like the following where the carriage return seems not working.
In order to 'activate' carriage return (which is actually line feed), you need to select a cell that you want to see carriage return, click somewhere in the formula bar, and you will notice the carriage return is 'activated'.
Copy the format of that cell and paste to the rest of the table using Format Painter to get the following:
If you are unclear about the above step, please read this article: How to display Power Query results with line feed or carriage return
All done. Cheers :)
By the way here are the codes behind the scene for reference only:
let
Source = Excel.CurrentWorkbook(){[Name="Table3"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Staff", type text}, {"Task", type text}, {"Status", type text}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "Staff+Status", each [Staff]&"+"&[Status]),
#"Grouped Rows" = Table.Group(#"Added Custom", {"Staff+Status"}, {{"Task", each Text.Combine([Task],"#(lf)"), type text}}),
#"Split Column by Delimiter" = Table.SplitColumn(#"Grouped Rows", "Staff+Status", Splitter.SplitTextByDelimiter("+", QuoteStyle.Csv), {"Staff+Status.1", "Staff+Status.2"}),
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Staff+Status.1", type text}, {"Staff+Status.2", type text}}),
#"Pivoted Column" = Table.Pivot(#"Changed Type1", List.Distinct(#"Changed Type1"[#"Staff+Status.2"]), "Staff+Status.2", "Task"),
#"Renamed Columns" = Table.RenameColumns(#"Pivoted Column",{{"Staff+Status.1", "Staff"}})
in
#"Renamed Columns"

Keeping track of "No Shows" on roster

Currently I am making a schedule of class times where the secretary adds names to the list for however many seats are available for that room, and it shows whether or not they have passed the test already. The managers would like a count of how many times the physician may have no showed. Column A is the seat number (plays no real role), column B is the name slot, which pulls a searchable list from a master list, with the "=Cell("contents")" trick because there are too many for a straight drop down. Column C is at VLOOKUP to check their current test status to help not double book. And finally, Column D is a checkbox if they no show.
I have a separate sheet that is keeping track of these no shows, it records the name, a count of 1, and the date they skipped.
Question 1, is there a way to not have to make each checkbox individually and link each individually? There's 8 weeks of class with 60+ seats.
Question 2, is there a way to make it add rows to this sheet only if checked off so there isn't 900 blank rows for a pivot table?
Code used on "NoShow" sheet:
=IF(Schedule!D5=TRUE,Schedule!B5,"")
=IF(A2<>"","1","")
=IF(Schedule!D5=TRUE,TODAY(),"")
This can be done easier with Power Query. In this example, I have:
One table on each worksheet, for each training date. No shows are indicated with "Yes".
Each table is named t_ and the table name.
Then Power Query consolidates all of the tables into one and produces one table showing all of the consolidated records, that is summarized with a pivot table, and another with unique names, that can be used for your drop-down menu.
When you have a new date, just add a new worksheet with a table for that date, fill in the info and Refresh the calculations.
Here is the table of consolidated data...
Here is the pivot that counts the no shows...
To get the summary table...
After you set up your tables, insert a blank query by going to Data > Get and Transform Data > Get Data > From Other Sources > Blank Query.
Then click Advanced Editor, delete any existing text and paste this:
let
Source = Excel.CurrentWorkbook(),
#"Filtered Rows" = Table.SelectRows(Source, each ([Name] <> "Summary")),
#"Expanded Content1" = Table.ExpandTableColumn(#"Filtered Rows", "Content", {"Seat Number", "Name of Physician", "No Show?"}, {"Seat Number", "Name of Physician", "No Show?"}),
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded Content1", "Name", "Name - Copy"),
#"Removed Columns" = Table.RemoveColumns(#"Duplicated Column",{"Seat Number"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Name - Copy", "Date"}}),
#"Extracted Text After Delimiter" = Table.TransformColumns(#"Renamed Columns", {{"Date", each Text.AfterDelimiter(_, "_"), type text}}),
#"Changed Type" = Table.TransformColumnTypes(#"Extracted Text After Delimiter",{{"Date", type date}}),
#"Reordered Columns" = Table.ReorderColumns(#"Changed Type",{"Name", "Date", "Name of Physician", "No Show?"}),
#"Renamed Columns1" = Table.RenameColumns(#"Reordered Columns",{{"Name", "Table Name"}})
in
#"Renamed Columns1"
Then click Close and Load To > New Worksheet.
To get the unique names table....
Follow the same steps above, but in a new blank query, paste this text...
let
Source = Excel.CurrentWorkbook(),
#"Filtered Rows" = Table.SelectRows(Source, each ([Name] <> "Summary")),
#"Expanded Content1" = Table.ExpandTableColumn(#"Filtered Rows", "Content", {"Seat Number", "Name of Physician", "No Show?"}, {"Seat Number", "Name of Physician", "No Show?"}),
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded Content1", "Name", "Name - Copy"),
#"Removed Columns" = Table.RemoveColumns(#"Duplicated Column",{"Seat Number"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Name - Copy", "Date"}}),
#"Extracted Text After Delimiter" = Table.TransformColumns(#"Renamed Columns", {{"Date", each Text.AfterDelimiter(_, "_"), type text}}),
#"Changed Type" = Table.TransformColumnTypes(#"Extracted Text After Delimiter",{{"Date", type date}}),
#"Reordered Columns" = Table.ReorderColumns(#"Changed Type",{"Name", "Date", "Name of Physician", "No Show?"}),
#"Renamed Columns1" = Table.RenameColumns(#"Reordered Columns",{{"Name", "Table Name"}}),
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns1",{"No Show?", "Date", "Table Name"}),
#"Removed Duplicates" = Table.Distinct(#"Removed Columns1")
in
#"Removed Duplicates"
Then Close and Load To > New Worksheet.
Then you can select the data in summary table and Insert Pivot Table. Add the names to the Rows section and the No Shows to the Values section. In the Row Labels column header, click Value Filters > Greater Than 0 (to remove the blanks). With the pivot table, you can double-click on the number of no shows and a new worksheet will be created, showing you where that calculation came from, so there's not need for the hyperlink.
Question 1, is there a way to not have to make each checkbox individually and link each individually? There's 8 weeks of class with 60+ seats.
Yes! See proposed system solution below.
Question 2, is there a way to make it add rows to this sheet only if checked off so there isn't 900 blank rows for a pivot table?
Yes, format the range you are using as a "Table" and the table adds rows automatically. Use in conjunction with proposed solution.
Proposed Solution:
You should be able to find a solution with PowerPivot using (i) a simple data model comprised of one table (fact table) tracks the class dates and people who miss the class and a master list of potential attendees (lookup/dimension table), where you relate the class tracking table to the potential attendee table via the name and (ii) a pivot table that easily summarizes who has missed. From the Pivot Table, you can create cool charts or slides as needed
Your secretary merely has to update changes in the fact table or dimension table. If the seat number plays no real purpose, it makes sense to leave it out.
Fact Table Columns: Date, Name, Missed (assign 1)
Dimension/LookUpTable Columns: Name, Test Taken, (other relevant info)
Note, you are using the entire name(first name and last name) in one cell. If you want to be rigorous, you may want to assign each name it's own unique ID and use that as the primary key for the LookUp table in the case there are two identical names.
Hopes this helps!

How to replace a column name in Power Query by a variable to filter rows?

In a query developed with Excel Power Query I would like to replace the table column name with a variable, when I filter rows of a list. Unfortunately, I either get an error message (e.g. Expression Error: Column xx of table was not found) or no row is remaining after filtering even if it should.
In the example below the variable #"Filter" (= column name) is set to column "B" and used in the step #"Filter Rows" to filter the rows which contain a '1'. But the result is that no row is shown.
Any idea what's the reason and how to solve this? Maybe the variable needs to have a special data type?
Thanks in advance!
Table:
Table to be filtered
Code:
let
#"Filter" = "B",
Source = Excel.CurrentWorkbook(){[Name="Tabelle2"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"A", Int64.Type}, {"B", Int64.Type}}),
#"Changed Type1" = Table.TransformColumnTypes(#"Changed Type",{{#"Filter", type text}}),
#"Filtered Rows" = Table.SelectRows(#"Changed Type1", each Text.Contains(#"Filter", "1"))
in
#"Filtered Rows"
#"Filter" is the value "B", so the condition always returns false. The second parameter of Table.SelectRows takes a function which passes in the current row of the table as a record. You can do either of the following to use a variable to specify the column:
= Table.SelectRows(#"Changed Type", each Text.Contains(Record.Field(_, #"Filter"), "1"))
= Table.SelectRows(#"Changed Type", (x) => Text.Contains(Record.Field(x, #"Filter"), "1"))
each and _ are the same as (x) => and x in these cases. Record.Field(_, #"Filter") gets the value in the current row for the column #"Filter" refers to.

Resources