Excel - Power Query 2016 - excel

I got data from two tables.
Customers (containing customer ID and the total value of orders/funding
Orders (Containing customer ID and each order)
I created a Power Query, then chose the option to "Merge Queries as New". Selected the matching Columns (Customer ID) and chose the option:Left Outer (All from the first and, matching from second => All from the customer table, matching from the order table). Then I expanded the last column of the Query to include what I wanted from the Order table resulting in the table below on the left. The one on the right is what I'm after. The problem is that funding amounts are already totals per customer. I don't need the value of each order broken down. I still need the orders displayed but I don't need their values (just the total per customer). Is it possible to do it like the one below on the right? Otherwise, the grand total is way off.

I think what you're trying to do is join with only the first instance of each value in your Customer column. There doesn't appear to be any feature or GUI element that allows you to do that (I had a look at the reference documentation for Power Query M, maybe I missed something).
To replicate your data, I'm starting off with some tables (left table is namedCustomers, right table is namedOrders):
I then use the M code below (the first few lines are just to get my tables from the sheet):
let
customers = Excel.CurrentWorkbook(){[Name = "Customers"]}[Content],
orders = Excel.CurrentWorkbook(){[Name = "Orders"]}[Content],
merged = Table.NestedJoin(orders, {"CUSTOMER"}, customers, {"CUSTOMER"}, "merged", JoinKind.LeftOuter),
indexColumn = Table.AddIndexColumn(merged, "Temporary", 0, 1),
indexes =
let
uniqueCustomers = Table.Distinct(Table.SelectColumns(indexColumn, {"CUSTOMER"})), // Want to keep as table
listOfRecords = Table.ToRecords(uniqueCustomers),
firstOccurenceIndexes = List.Accumulate(listOfRecords, {}, (listState, currentItem) =>
List.Combine({listState, {Table.PositionOf(indexColumn, currentItem, Occurrence.First, "CUSTOMER")}})
)
in
firstOccurenceIndexes,
expandSelectively =
let
toBoolean = Table.TransformColumns(indexColumn, {{"Temporary", each List.Contains(indexes, _), type logical}}),
tableOrNull = Table.AddColumn(toBoolean, "toExpand", each if [Temporary] then [merged] else null),
dropRedundantColumns = Table.RemoveColumns(tableOrNull, {"merged", "Temporary"}),
expand = Table.ExpandTableColumn(dropRedundantColumns, "toExpand", {"FUNDING"})
in
expand
in
expandSelectively
If your table names and column names match mine (including case sensitivity), then you might just be able to copy-paste all of the M code above into the Advanced Editor and have it work for you. Otherwise, you may need to tweak as necessary.
This is what I get when I load the query to the worksheet.
There might be better (more efficient) ways of doing this, but this is what I have for now.

If you're not using the order ID column, then I would suggest doing a Group By on the OrderTable before merging in the funding so that you'd end up with a table like this instead:
Region Customer OrderCount Funding
South A 3 2394
South B 2 4323
South C 1 1234
South D 2 3423
This way you don't have mixed levels of granularity that cause problems like you are seeing with the totals.

Related

M Query Table.Group with Min based on two columns

I have a table with many columns. Three of these columns are:
Package Name (text)
Units Required (Int.64)
Assessment (Int.64)
What I am trying to do is to find the 'Minimum' "Package Name" first by selecting the smallest number of "Units Required", then because sometimes there are several instances where the number of required units will be the same, the row with the lowest "Assessment".
I am exploring the Table.Group() approach but I am not getting anywhere with my understanding of it. I am doing this in Power Query in Excel 365.
Psuedo Code would be something like:
Table.Group("Previous Step Name",{"Package Name"},{MIN("Units Required"),MIN("Assessment")})
As an aside - is it possible to use a single Table.Group and group at two levels? such as "Package Name" and "Column X" so that the result would be a: for each "Package Name" then for each "Column X" in each "Package Name" (nested as it were).
Thankyou in advance for taking a look at this.
Any help greatly appreciated.
Cheers
The Frog
I think you have to do it step by step.
Data
Queries
Load_Data
Load data from Excel table
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content]
in
Source
Min_Unit
Identify min unit by grouping with empty "group by" field.
let
Source = Load_Data,
Group = Table.Group(Source, {}, {{"Min_Unit", each List.Min([Units Required]), type number}})
in
Group
Min_Unit_And_Assessment
Use inner join to filter original data for entries which equal min_unit. Next, group by "units required" to get the min_assessment.
let
Source = Table.NestedJoin(Load_Data, {"Units Required"}, Min_Unit, {"Min_Unit"}, "Min_Unit", JoinKind.Inner),
Group = Table.Group(Source , {"Units Required"}, {{"Min_Assessment", each List.Min([Assessment]), type nullable number}})
in
Group
Result
Inner join to filter original data for the combination of min_unit and min_assessment.
let
Source = Table.NestedJoin(Load_Data, {"Units Required", "Assessment"}, Min_Unit_And_Assessment, {"Units Required", "Min_Assessment"}, "Min_Unit_And_Assessment", JoinKind.Inner),
RemoveUnnecessaryColumns = Table.RemoveColumns(Source,{"Min_Unit_And_Assessment"})
in
RemoveUnnecessaryColumns
Result
Qualia, thankyou for pointing me in the right direction.
The way that I solved this was really simple in the end!
Step 1: Sort the rows based on the grouping criteria (package name, system class) in that order
Step 2: Add an Index Column so each row has a unique ID to work with
Step 3: Group the table based on the same fields (package name, system class) and 'aggregate' on the lowest Index Number (MIN)
Step 4: Perform a 'Merge Queries' with a Left Outer Join using the Index Number as the matching field between your current 'step' and the step from earlier in the processing where the Index was added - you can then have the rows matched and only the rows needed will be matched since the others are now gone due to the MIN aggregation from earlier. Here is my example:
Table.NestedJoin(#"Grouped Rows", {"Winner"}, #"Added Index", {"Index"}, "Lookup Data", JoinKind.LeftOuter)
- Grouped Rows was the grouping step (Step 3)
- Winner is the name of the Index that had the minimum value
- Added Index was the last step before grouping that still had all the columns (Step 2)
- Index is the column that was added after the sort to uniquely number each row
Step 5: Expand the table and select the columns of data that you want to hang onto
Treating it a bit like a database was a good approach and I appreciate the suggestion you put together for me. Hopefully this will allow others to solve some of their problems too.
Cheers and many thanks
The Frog

Comparing Multiple Lists of Data in Excel to find gaps

I am conducting a product analysis and have data on all the products my company has and need to compare that against all the products that our competitors have. I need to find out where the gaps are, in particular what products do they have that we don't? from the multiple lists of data I have on each competitors products lists against our product data list.
What is the best formula to use or way to find and interpret this data in Excel?
Thanks
Join the tables using Power query.
Table 1 = your company
key = Product
Table2 through TableN= competitors
key = Product
Combine the competitors tables into a single table.
Do a nestedjoin with JoinKind.RightAnti which will return all the products in Table 2 that do not exist in Table 1
We use a Nested join since the keys have the same Column Header
M Code
You can paste this code into the Power Query Advanced Editor, and change the Name= argument in lines 2 through N to reflect your actual table names
If you have many competitors, it is possible to create a function to gather all the table names, but overkill for just a few
Step through Applied Steps in the Power Query UI to see what each line does.
let
myCompany = Excel.CurrentWorkbook(){[Name="myCompany"]}[Content],
otherCompany = Excel.CurrentWorkbook(){[Name="otherCompany"]}[Content],
company3 = Excel.CurrentWorkbook(){[Name="company3"]}[Content],
//Join the competitor tables
competitors = Table.Combine({otherCompany,company3}),
//finde the missing
missing = Table.NestedJoin(myCompany,"Product",competitors,"Product", "Missing", JoinKind.RightAnti),
#"Removed Columns" = Table.RemoveColumns(missing,{"Product", "Description"}),
#"Expanded Missing" = Table.ExpandTableColumn(#"Removed Columns", "Missing", {"Product", "Description"}, {"Missing.Product", "Missing.Description"}),
#"Sorted Rows" = Table.Sort(#"Expanded Missing",{{"Missing.Product", Order.Ascending}})
in
#"Sorted Rows"
You should definitely do this type of comparison in a different system than Excel.
However, if you definitely want to do it in Excel and only want to compare the products, you can do it like this:
1 Sheet contains a table with all the competitors products.
If the competitor is also important to know, then add that too...
A
B
1
product a
competitor a
2
product b
competitor b
3
product c
competitor a
Then use 1 Sheet with a list of your product and a vlookup to check if the competitor has it. You also add vlookup to the competitor list to see if you have what they got.
Your products list:
A
B
1
product a
=vlookup(A1;$Sheet1.A:B;2;FALSE)
2
product b
=vlookup(B1;$Sheet1.A:B;2;FALSE)
3
product c
=vlookup(AC;$Sheet1.A:B;2;FALSE)
Column B will show which competitor has this.
Add the same kind of vlookup to the competitor too.
Depending on your Excel version, it could be that you should use , instead of ; and the vlookup could be called something in a different language.

UOM and UOM ratio incorrect on Pick Ticket

We use UOM conversions at this client. We stock in Eaches and sell in Cases. The problem we are having with the Pick ticket is that both the quantity to be picked and the UOM being picked are the stocking unit and not the selling unit.
e.g. The customer orders 73 cases (12 ea per case). The pick ticket prints 876 each. This requires the warehouse person to look up each item determine if there is a Selling UOM and ratio and to then manually convert 876 eaches to 73 cases.
Obviously, the pick ticket should print 73 cases. But I cannot find a way to do this. The items are lotted and an order of 73 case might have 50 cases of Lot A and 23 cases of Lot B. This is represented in the SOShipLineSplit table. The quantities and UOM in this table are based on Stocking units.
Ideally, I could join the INUnits table to both the SOSHipLine and SOShipLineSPlit table. See Below.
Select case when isnull(U.UnitRate,0) = 0 then S.Qty else S.Qty/U.Unitrate end as ShipQty
,case when isnull(U.UnitRate,0) = 0 then s.uom else U.FromUnit end as UOM
from SOShipLineSplit S
inner join SOShipLine SL
ON S.CompanyID = SL.CompanyID and s.ShipmentNbr = SL.ShipmentNbr and S.LineNbr = SL.LineNbr and S.InventoryID = SL.InventoryID
Left Outer Join INUnit U
On S.CompanyID = U.CompanyID and S.InventoryID = U.InventoryID and s.UOm = U.ToUnit and SL.UOM = U.FromUnit
where S.ShipmentNbr = '000161' and S.CompanyId = 4
The problem is the Acumatica Report writer does not support a join with multiple tables.
Left Outer Join INUnit U
On S.CompanyID = U.CompanyID and S.InventoryID = U.InventoryID and s.UOm = U.ToUnit and SL.UOM = U.FromUnit
I believe I must be missing something. This cannot be the only client using Acumatica who utilizes Selling Units of Measure. Is there another table I could use that would contain the quantities and UOM already converted for this order to Selling Units?
Or another solution?
Thanks in advance.
pat
EDIT:
If the goal is to display accurate quantities before/after conversion then INUnit DAC can't be used. It doesn't store historical data, you can change INUnit values after an order has been finalized so re-using it to compute quantities will not yield accurate results.
For that scenario you would need to use the historical data fields with Base prefixes like ShippedQuantity/BaseShippedQuantity. If you require to store more historical data you need to add a custom field to hold these values and update them when shipment is created/modified.
The main issue appears to be a logical error in the requirement:
The problem is that the INUnit table has to be joined to BOTH the
SOShipLine and the SOShipLineSplit tables.
INUnit DAC has a single parent, not 2 so you need to change your requirement to reflect that constraint.
If SOShipLine and SOShipLineSplit values differ then you'll never get any record.
If they are identical then there's no need to join on both since they have the same value.
I suggest to add 2 joins, one for SOShipLine and another for SOShipLineSplit. In the report you can choose which one to display (1st, 2nd or both).
You can also add visibility conditions or IIF formula condition in the report if you want to handle null values error check for display purpose.
Use the Child Alias property in schema builder to join the same table 2 times without name conflicts. In the report formulas (to display field or in formula conditions) use the Child Alias table name too.
Example:

Cleaning Excel Table using VBA without impacting the entire table and formatting

Hi I am trying to change to write VBA for excel to clean up data elements that has extra information without impacting the other elements.
I am writing VBA for the first time my table is in the middle of the sheet.
Given Table and Requested Output.
I think your question was not clear in regard to the "steps" that you want to perform on your data (i.e. the exact logic or transformation that needs to be applied).
Based purely on your images and your comment, I make the "steps" to be:
Split any customer IDs in column valueC into multiple rows.
If column valueC does not contain customer IDs (i.e. is blank or contains non-customer ID text), leave it untouched.
My answer uses Power Query instead of VBA. If you are interested in trying it out, in Excel try clicking Data > Get Data > From Other Sources > Blank Query, then click Advanced Editor near the top-left, copy-paste the code below, then click Done.
You might need to change the name of the table in the first line of the code (below), as it was "Table1" for me, but I imagine yours is named something else. Also, the code below is case-sensitive. So if there is no column named exactly valueC, then you will get an error.
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
fxProcessSomeText = (textToProcess as any) =>
let
canBeSplit = Text.StartsWith(textToProcess, "### customer id"),
result = if textToProcess is null then null else if canBeSplit then Text.Split(Text.BetweenDelimiters(textToProcess, "### customer id", " ###"), ",") else {textToProcess}
in
result,
invokeFunction = Table.TransformColumns(Source, {{"valueC", fxProcessSomeText}}),
expanded = Table.ExpandListColumn(invokeFunction, "valueC"),
reindex =
let
removeIndex = Table.RemoveColumns(expanded, {"index"}),
addIndex = Table.AddIndexColumn(removeIndex, "index", 1, 1),
moveIndex = Table.ReorderColumns(addIndex, List.Distinct(List.InsertRange(Table.ColumnNames(addIndex), 0, {"index"})))
in
moveIndex
in
reindex
My output table contains more rows than yours. Also, the value in column valueA, row 11 is 1415 for me (it is 1234 in your request output). Not sure if this is a mistake in your example, or if I'm missing some logic.

Power Query - Keeping Most recent records in change log columns

I need to strip records to show just the most recent for a given person, and I'm trying to think of a method for doing this in a custom column so I can just keep the most recent records. This is essentially a a status change list, and I need to match the last change as a "current status" for merging with another query. Each date can be unique, and each person can have any from 1 to a dozen status changes. I've picked a selection below, Last Names have been removed to protect the innocent. For sake of the example, Each "name" has a unique identifier that I can use to prevent any overlap from similar names.
AaronS 4/1/2015
AaronS 10/16/2013
AaronS 5/15/2013
AdamS 2/27/2007
AdamL 12/16/2004
AdamL 11/17/2004
AlanG 11/1/2007
AlexanderJ 7/1/2016
AlexanderJ 1/25/2016
AlexanderJ 4/1/2015
AlexanderJ 10/16/2013
AlexanderJ 6/1/2013
AlexanderJ 11/7/2011
My goal would be to return the most recent date for each individual "name" and nulls for the other rows. Then I can filter out nulls to return one row per name. I'm fairly new to power query and mostly adept with the UI, barely learning M Code. Any help will be most welcome.
GUI
Bring the "Name" and "Date" data into Power Query.
Group by "Name". In the Group By dialog select the operation All Rows. Name the new column "AllRows". Click OK.
Add a custom column and title it "LatestRow". Enter the formula below. Click OK. Note that the "Date" column is coming from the sub-table in the "AllRows" column.
= Table.Max([AllRows], "Date")
Click the expand button in the upper right corner of the "LatestRow" column. This will return the record associated with the latest date for each name.
Code
let
Source = Excel.CurrentWorkbook(){[Name="data"]}[Content],
GroupedRows = Table.Group(Source, {"Name"}, {{"AllRows", each _, type table [Name=nullable text, Date=nullable datetime]}}),
AddedCustomColumn = Table.AddColumn(GroupedRows, "LatestRow", each Table.Max([AllRows], "Date")),
ExpandedLatestRow = Table.ExpandRecordColumn(AddedCustomColumn, "LatestRow", {"Date"}, {"LatestRow.Date"})
in
ExpandedLatestRow

Resources