PowerPivot: Join tables with multiple data - powerquery

I dont know if it is possible, but i have 3 tables in PowerPivot:
each table reflects the history of one worker per store and per department and per function.
User Store DateChangeStore
User 1 Store 1 01/01/2019
User 1 Store 2 01/05/2019
User Dept DateChangeDpt
User 1 Dept 1 01/01/2019
User 1 Dept 2 01/03/2019
User 1 Dept 1 01/06/2019
User Function DateChangeFct
User 1 Func 1 01/01/2019
User 1 Func 2 01/02/2019
And i want to transform into one table like this below, but the twist is that I want to relate with the date.
Per example:
user 1 when entered we was on store 1, department 1 with function 1.
But when he changed to function 2, he was still on store 1 and department 1...
Is possible to see by the change date.
User Store DateChangeStore Dept DateChangeDpt Function DateChangeFct
User 1 Store 1 01/01/2019 Dept 1 01/01/2019 Func 1 01/01/2019
User 1 Store 1 01/01/2019 Dept 1 01/01/2019 Func 2 01/02/2019
User 1 Store 1 01/01/2019 Dept 2 01/03/2019 Func 2 01/02/2019
User 1 Store 2 01/05/2019 Dept 2 01/03/2019 Func 2 01/02/2019
User 1 Store 2 01/05/2019 Dept 1 01/06/2019 Func 2 01/02/2019
Is this possible in any way?
thank you
-- UPDATE --
i Only gave an example with 1 user, but the original data as multiple users:
example below
User Store DateChangeStore
User 1 Store 1 01/01/2019
User 1 Store 2 01/05/2019
User 2 Store 1 01/06/2019
User Dept DateChangeDpt
User 1 Dept 1 01/01/2019
User 1 Dept 2 01/03/2019
User 1 Dept 3 01/06/2019
User 2 Dept 1 01/06/2019
User 2 Dept 2 01/07/2019
User Function DateChangeFct
User 1 Func 1 01/01/2019
User 1 Func 2 01/02/2019
User 2 Func 1 01/06/2019

Initial attempt at a solution in Power Query might be something like:
let
storeTable = Table.FromColumns({{"User 1", "User 1"}, {"Store 1", "Store 2"}, {#date(2019, 1, 1), #date(2019, 5, 1)}}, {"User", "Store", "DateChangeStore"}),
deptTable = Table.FromColumns({{"User 1", "User 1", "User 1"}, {"Dept 1", "Dept 2", "Dept 3"}, {#date(2019, 1, 1), #date(2019, 3, 1), #date(2019,6,1)}}, {"User", "Dept", "DateChangeDept"}),
funcTable = Table.FromColumns({{"User 1", "User 1"}, {"Func 1", "Func 2"}, {#date(2019, 1, 1), #date(2019, 2, 1)}}, {"User", "Function", "DateChangeFct"}),
distinctDates = List.Distinct(storeTable[DateChangeStore] & deptTable[DateChangeDept] & funcTable[DateChangeFct]),
columnOfDates = Table.FromColumns({distinctDates}, type table [changeDate = date]),
joinedStore = Table.NestedJoin(columnOfDates, {"changeDate"}, storeTable, {"DateChangeStore"}, "toExpand", JoinKind.LeftOuter),
expandedStore = Table.ExpandTableColumn(joinedStore, "toExpand", {"User", "Store", "DateChangeStore"}, {"User", "Store", "DateChangeStore"}),
joinedDept = Table.NestedJoin(expandedStore, {"changeDate"}, deptTable, {"DateChangeDept"}, "toExpand", JoinKind.LeftOuter),
expandedDept = Table.ExpandTableColumn(joinedDept, "toExpand", {"DateChangeDept"}),
joinedFunction = Table.NestedJoin(expandedDept, {"changeDate"}, funcTable, {"DateChangeFct"}, "toExpand", JoinKind.LeftOuter),
expandedFunction = Table.ExpandTableColumn(joinedFunction, "toExpand", {"DateChangeFct"}),
sorted = Table.Sort(expandedFunction,{{"changeDate", Order.Ascending}}),
filledDown = Table.FillDown(sorted,{"User", "Store", "DateChangeStore", "DateChangeDept", "DateChangeFct"})
in
filledDown
which gives me the following:
which appears to match the example you've given in your question (as far as I can see). (Also, try testing with some different data to see if output is still correct and as expected.)
If everything's okay with output, code can be refined (to avoid repetition) into something like:
let
// You don't need the lines below (I only use them to generate the data in the example). You should replace them with your own tables/code.
storeTable = Table.FromColumns({{"User 1", "User 1"}, {"Store 1", "Store 2"}, {#date(2019, 1, 1), #date(2019, 5, 1)}}, {"User", "Store", "DateChangeStore"}),
deptTable = Table.FromColumns({{"User 1", "User 1", "User 1"}, {"Dept 1", "Dept 2", "Dept 3"}, {#date(2019, 1, 1), #date(2019, 3, 1), #date(2019,6,1)}}, {"User", "Dept", "DateChangeDept"}),
funcTable = Table.FromColumns({{"User 1", "User 1"}, {"Func 1", "Func 2"}, {#date(2019, 1, 1), #date(2019, 2, 1)}}, {"User", "Function", "DateChangeFct"}),
columnOfDates =
let
allDates = storeTable[DateChangeStore] & deptTable[DateChangeDept] & funcTable[DateChangeFct],
deduplicated = List.Distinct(allDates),
asTable = Table.FromColumns({deduplicated}, type table [changeDate = date])
in asTable,
LeftJoinAndExpand = (leftTable as table, leftJoinColumn as text, rightTable, rightJoinColumn, expandAllInRightTable as logical) =>
let
joined = Table.NestedJoin(leftTable, {leftJoinColumn}, rightTable, {rightJoinColumn}, "$toExpand", JoinKind.LeftOuter),
columnsToExpand = if expandAllInRightTable then Table.ColumnNames(rightTable) else {rightJoinColumn},
expanded = Table.ExpandTableColumn(joined, "$toExpand", columnsToExpand)
in expanded,
joinedStore = LeftJoinAndExpand(columnOfDates, "changeDate", storeTable, "DateChangeStore", true),
joinedDept = LeftJoinAndExpand(joinedStore, "changeDate", deptTable, "DateChangeDept", false),
joinedFunc = LeftJoinAndExpand(joinedDept, "changeDate", funcTable, "DateChangeFct", false),
sorted = Table.Sort(joinedFunc, {{"changeDate", Order.Ascending}}),
filledDown = Table.FillDown(sorted, {"User", "Store", "DateChangeStore", "DateChangeDept", "DateChangeFct"})
in
filledDown
And for multiple users:
You could try something like:
let
storeTable = Table.FromColumns({{"User 1", "User 1", "User 2"}, {"Store 1", "Store 2", "Store 1"}, {#date(2019, 1, 1), #date(2019, 5, 1), #date(2019, 6, 1)}}, type table [User = text, Store = text, DateChangeStore = date]),
deptTable = Table.FromColumns({{"User 1", "User 1", "User 1", "User 2", "User 2"}, {"Dept 1", "Dept 2", "Dept 3", "Dept 1", "Dept 2"}, {#date(2019, 1, 1), #date(2019, 3, 1), #date(2019, 6, 1), #date(2019, 6, 1), #date(2019, 7, 1)}}, type table [User = text, Dept = text, DateChangeDept = date]),
funcTable = Table.FromColumns({{"User 1", "User 1", "User 2"}, {"Func 1", "Func 2", "Func 1"}, {#date(2019, 1, 1), #date(2019, 2, 1), #date(2019, 6, 1)}}, type table [User = text, Function = text, DateChangeFct = date]),
// You don't need the lines above (I only use them to generate the data in the example).
// You should replace them with your own tables/code.
renamePairs = {{"DateChangeStore", "$changeDate"}, {"DateChangeDept", "$changeDate"}, {"DateChangeFct", "$changeDate"}},
toCombine = List.Transform({storeTable, deptTable, funcTable}, each Table.SelectColumns(Table.RenameColumns(_, renamePairs, MissingField.Ignore), {"User", "$changeDate"})),
combined = Table.Distinct(Table.Combine(toCombine), {"User", "$changeDate"}),
LeftJoinAndExpand = (leftTable as table, leftJoinKeys as list, rightTable as table, rightJoinKeys as list) as table =>
let
joined = Table.NestedJoin(leftTable, leftJoinKeys, rightTable, rightJoinKeys, "$toExpand", JoinKind.LeftOuter),
columnsToExpand = List.Difference(Table.ColumnNames(rightTable), Table.ColumnNames(leftTable)),
expanded = Table.ExpandTableColumn(joined, "$toExpand", columnsToExpand)
in expanded,
groupedAndJoined = Table.Group(combined, {"User"}, {"$toExpand", (userTable) =>
let
joinedStore = LeftJoinAndExpand(userTable, {"User", "$changeDate"}, storeTable, {"User", "DateChangeStore"}),
joinedDept = LeftJoinAndExpand(joinedStore, {"User", "$changeDate"}, deptTable, {"User", "DateChangeDept"}),
joinedFunc = LeftJoinAndExpand(joinedDept, {"User", "$changeDate"}, funcTable, {"User", "DateChangeFct"})
in joinedFunc
, type table}),
// Am doing this as a separate step (rather than in previous step) only so that the JOIN results can be previewed in Query Editor.
fillDownNestedTables = Table.TransformColumns(groupedAndJoined, {"$toExpand", (userTable) =>
let
sorted = Table.Sort(userTable, {{"User", Order.Ascending}, {"$changeDate", Order.Ascending}}),
columnsToFill = List.RemoveMatchingItems(Table.ColumnNames(sorted), {"User", "$changeDate"}),
filledDown = Table.FillDown(sorted, columnsToFill),
dropHelperColumn = Table.RemoveColumns(filledDown, {"$changeDate"})
in dropHelperColumn
, type table}),
expandNestedTables =
let
allHeaders = List.Combine(List.Transform(Table.Column(fillDownNestedTables, "$toExpand"), Table.ColumnNames)),
columnsToExpand = List.Difference(List.Distinct(allHeaders), Table.ColumnNames(fillDownNestedTables)),
expanded = Table.ExpandTableColumn(fillDownNestedTables, "$toExpand", columnsToExpand)
in expanded
in
expandNestedTables
which gives me:
which I think is correct (but I'm not sure if the logic/transformation/approach is as efficient as it could be).

Related

Counting customers that have sales in the same products

The data table has customers, products sales etc.
Based on a slicer selection products i want to count how many customers have sales in all selected products.
As below i only want to count customer B because he is the only one having all selected products
Customer a Product a product b product c
A. 1 1
B. 1 1 1
C. 1
D. 1 1
E. 1 1
OKay. I think Your table is this:
Then You need this dax code:
CustomerHavingAll3Products =
VAR Onlya =
CALCULATETABLE ( VALUES ( 'Product'[Customer] ), 'Product'[Product a] <> 0 )
VAR Onlyb =
CALCULATETABLE ( VALUES ( 'Product'[Customer] ), 'Product'[Product b] <> 0 )
VAR Onlyc =
CALCULATETABLE ( VALUES ( 'Product'[Customer] ), 'Product'[Product c] <> 0 )
VAR CombinedAll =
INTERSECT ( INTERSECT ( Onlya, Onlyb ), Onlyc )
RETURN
COUNTX ( CombinedAll, [Customer] )
If we test it on a table visual:
Please do not forget to click the down-pointing arrow on customer column on the filter pane, and ensure that "show items with no data" is checked, see the picture below
you can do it on power query side... totally dynamic...
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTIEYjAVqxOt5AQVMISLOMOkgRSI74KuxRVJi1JsLAA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Customer = _t, #"Product a" = _t, #"product b" = _t, #"product c" = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Customer", type text}, {"Product a", Int64.Type}, {"product b", Int64.Type}, {"product c", Int64.Type}}),
count_columns = Table.ColumnCount(Source)-1,
#"Unpivoted Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"Customer"}, "Attribute", "Value"),
#"Grouped Rows" = Table.Group(#"Unpivoted Columns", {"Customer"}, {{"Total Count", each Table.RowCount(_), Int64.Type}}),
#"Filtered Rows" = Table.SelectRows(#"Grouped Rows", each [Total Count] = count_columns )
in
#"Filtered Rows"

calculate differences between 2 smallests date for each ID

I have some users with different game_id.
for each user, I want to find differences between the 2 smallest different dates and write the result in another column.
in this example,
for user_id = 1, it should be 4 (difference between 13/2/2001 and 17/2/2001)
for user_id = 2, we don't have any result because we have just 1 date,
for user_id = 3, it should be 3
and for user_id = 4, it should be 3. (difference between 5/10/2003 and 8/10/2003)
How can I calculate it in Power BI?
This does the trick with M code if you feel like using
It groups on user_id, gets the 2 lowest dates from the unique values, and calculates the difference. It then merges back on original data into a new column
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"account_charging_dates", type date}}),
#"Grouped Rows" = Table.Group(#"Changed Type", {"user_id"}, {{"Diff", each try Number.From( List.MinN(List.Distinct([account_charging_dates]),2){1} - List.MinN(List.Distinct([account_charging_dates]),2){0}) otherwise null}}),
#"Merged Queries" = Table.NestedJoin(#"Changed Type",{"user_id"},#"Grouped Rows",{"user_id"},"Table1",JoinKind.LeftOuter),
#"Expanded Table1" = Table.ExpandTableColumn(#"Merged Queries", "Table1", {"Diff"}, {"Diff"})
in #"Expanded Table1"

Excel - use Power Query to separate one column into several columns based on another column

Let's say I have a table like this:
Var1 Group
1 A
2 B
3 A
4 B
5 A
I wish to have a table like this:
A B
1 2
3 4
5
How can I achieve this specifically using Power Query in Excel?
Try below
Right-click Group column and do Group By ...
Use the default option then change code in the formula box to resemble the below, especially after the each
= Table.Group(Source, {"Group"}, {{"xx", each Table.AddIndexColumn(_, "Index", 1, 1), type table}})
click on arrows atop the new column and [x] expand Var1 and Index
Click on Group column, Transform ... pivot columns .. and choose Var1 as Values Column
Erase extra index column
Full sample code:
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Grouped Rows" = Table.Group(Source, {"Group"}, {{"xx", each Table.AddIndexColumn(_, "Index", 1, 1), type table}}),
#"Expanded xx" = Table.ExpandTableColumn(#"Grouped Rows", "xx", {"Var1", "Index2"}, {"Var1", "Index"}),
#"Pivoted Column" = Table.Pivot(#"Expanded xx", List.Distinct(#"Expanded xx"[Group]), "Group", "Var1", List.Sum),
#"Removed Columns" = Table.RemoveColumns(#"Pivoted Column",{"Index2"})
in #"Removed Columns"

Is this possible in a power query?

Can I convert the original data into the format I want through Power Query? I'm not sure if it's possible with PowerQuery or if I need to implement it with VBA, so I really need your advice.
See if this works for you.
Assumes 4 columns in source data {Group A, Group B, Date, Value}
Basic Method [1] Group data by Date and GroupA, and add index [2] Create separate table that inverts Value, and add index [3] Join the two tables and remove original Value column [4] Remove extra columns [5] Expand [6] Pivot
Below code can be pasted into Powerquery in Home ... Advanced Editor ...
let Source = Excel.CurrentWorkbook(){[Name="Table3"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Group A", type text}, {"Group B", type text}, {"Date", type date}, {"Value", Int64.Type}}),
#"Sorted Rows" = Table.Sort(#"Changed Type",{{"Group A", Order.Ascending}, {"Date", Order.Ascending}, {"Group B", Order.Ascending}}),
// Group by Date and Group A, and add Index Column
#"Grouped Rows" = Table.Group( #"Sorted Rows" , {"Group A","Date"}, {{"Data", each Table.AddIndexColumn(_, "Index", 1, 1), type table}}),
//Create new table with inverted Values for each Group A Date, with index
#"Added Custom2" = Table.AddColumn(#"Grouped Rows", "Custom.2", each Table.AddIndexColumn(Table.FromList(List.Reverse(Table.Column([Data],"Value")) , Splitter.SplitByNothing(), null, null, ExtraValues.Error), "Index", 1, 1)),
//Join the two tables
#"Added Custom3" = Table.AddColumn(#"Added Custom2", "Custom.3", each Table.RemoveColumns(Table.Join([Data] , "Index", [Custom.2] , "Index", JoinSide.Left),{"Index","Value"})),
//Remove Excess Columns
#"Removed Columns1" = Table.RemoveColumns(#"Added Custom3",{"Group A", "Date", "Data", "Custom.2"}),
// Expand and pivot
#"Expanded Custom.3" = Table.ExpandTableColumn(#"Removed Columns1", "Custom.3", {"Group A", "Group B", "Date", "Column1"}, {"Group A", "Group B", "Date", "Column1"}),
#"Pivoted Column" = Table.Pivot(Table.TransformColumnTypes(#"Expanded Custom.3", {{"Date", type text}}, "en-US"), List.Distinct(Table.TransformColumnTypes(#"Expanded Custom.3", {{"Date", type text}}, "en-US")[Date]), "Date", "Column1", List.Sum)
in #"Pivoted Column"

How to display animals with all information?

I have four Tables. "Animals", "races", "animal_classes" and "animal_class_race".
Races and animal_classes are boring, only with "id" and "name".
The "animal_class_race" has: "id", "race_id", and "animal_class_id". Let us say: 1, 1, 1, and the timestamps
In "animal"-Table I have "id", "name" and "animal_class_race_id". Let us say: 1, bello, 1
What is the best way to show this animal with information from "race" and "animal_class"?
select animals.name as name, races.name as race, animal_classes.name as animal_class from animals a inner join animal_class_race acr on a.animal_class_race_id = acr.id inner join races r on r.id = acr.race_id inner join animal_classes ac on ac.id = acr.animal_class_id order by a.name

Resources