Weighted Average Cost in POWER QUERY - powerbi

Im new to power query and Im trying to calqulate Weighted Average Cost of materials.
When I receive a new stock, avarage price shoul be (Cost of Available Stock + Cost of New Stock) / Total Stock (Qty)
When we issue stock, the average price should be Cost of Available Stock / Available Stock (Qty)
I have following example table.
Is there any idea how to calculate the weighted average cost in this situation?
Thank you.

You can use the List.Generate function to generate both the Running Total Column as well as the Weighted Average Cost column.
Starting with:
M Code
let
//Change next line to reflect your actual data source
Source = Excel.CurrentWorkbook(){[Name="Table11"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Date", type date}, {"Type", type text},
{"In Price", Currency.Type}, {"Qty", Int64.Type}}),
#"Capitalized Each Word" = Table.TransformColumns(#"Changed Type",{{"Type", Text.Proper, type text}}),
#"Add Running Total Column" =
Table.FromColumns(
Table.ToColumns(#"Capitalized Each Word") &
{List.Generate(
()=>[rt=#"Capitalized Each Word"[Qty]{0}, idx=0],
each [idx] < Table.RowCount(#"Capitalized Each Word"),
each [rt = [rt] + #"Capitalized Each Word"[Qty]{[idx]+1}, idx=[idx]+1],
each [rt])},
type table[Date=date, Type=text, In Price=Currency.Type, Qty=Int64.Type, Running Total=Int64.Type]),
#"Add Avg Cost Column" =
Table.FromColumns(
Table.ToColumns(#"Add Running Total Column") &
{List.Generate(
()=>[cst=if #"Add Running Total Column"[Type]{0}="In" then #"Add Running Total Column"[In Price]{0} else null, idx=0],
each [idx] < Table.RowCount(#"Add Running Total Column"),
each [cst=if #"Add Running Total Column"[Type]{[idx]+1}="Out" then [cst]
else ((if [cst]=null then 0 else [cst]) * #"Add Running Total Column"[Running Total]{[idx]} +
#"Add Running Total Column"[In Price]{[idx]+1} * #"Add Running Total Column"[Qty]{[idx]+1})
/ #"Add Running Total Column"[Running Total]{[idx]+1} , idx=[idx]+1],
each [cst])},
type table[Date=date, Type=text, In Price=Currency.Type, Qty=Int64.Type, Running Total=Int64.Type, Avg Cost=Currency.Type])
in
#"Add Avg Cost Column"
results

Related

Create an average table excluding some values

I have a table with this structure:
Date
DeviceID
Value
01/01/2022
SensorA
1200
01/01/2022
SensorB
1300
01/01/2022
SensorC
900
02/01/2022
SensorA
500
02/01/2022
SensorB
50
02/01/2022
SensorC
39
I'm interesting in create a new table that have the average by day of all sensors values but excluding the values which are lower than the average of all sensors by day.
For example for 01/01/2022 the average of all sensors values is:
(1200+1300+900) / 3 = 1133.3
We then calculate the average sensor value for the day, excluding SensorC because its value is below 1133.3:
(1200+1300) / 2 = 1250
The final table have to looks like this:
Date
Value
01/01/2022
1250
02/01/2022
500
Is it possible? Hope you can help me
Thanks in advance!
This does exactly what you are asking for:
Avg Excl =
VAR _avg = AVERAGE ( 'Table'[Value] )
RETURN
CALCULATE (
AVERAGE ( 'Table'[Value] ) ,
'Table'[Value] > _avg
)
Result:
If you want to persist a DAX table to your model, you just use this code together with SUMMARIZE:
New_Table =
SUMMARIZE (
'Table' ,
'Table'[Date] ,
"Value",
VAR _avg = AVERAGE ( 'Table'[Value] )
RETURN
CALCULATE (
AVERAGE ( 'Table'[Value] ) ,
'Table'[Value] > _avg
)
)
Result:
For good measure, here is some Power Query code to achieve the same result. Usually this is best practice due to compression efficiency and such in Power BI. As a bonus, it also makes working with the pbix file smoother since you don't have to wait for the table to recalculate all the time when you add/remove/edit DAX components.
This solution is your best bet if this his how you actually want your table to look, since you can get rid of the original table in the model altogether and not have it in the model as a dependency. You can paste this into a blank query:
let
Source = Table.FromRecords({
[Date="2022-01-01", DeviceID="SensorA",Value=1200],
[Date="2022-01-01", DeviceID="SensorB",Value=1300],
[Date="2022-01-01", DeviceID="SensorC",Value=900],
[Date="2022-01-02", DeviceID="SensorA",Value=500],
[Date="2022-01-02", DeviceID="SensorB",Value=50],
[Date="2022-01-02", DeviceID="SensorC",Value=39]
}),
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"Date", type date},
{"DeviceID", type text},
{"Value", Int64.Type}
}),
#"Grouped Rows" = Table.Group(#"Changed Type", {"Date"}, {
{"Avg", each List.Average([Value]), type nullable number},
{"Data", each _, type table [Date=nullable date, DeviceID=nullable text, Value=nullable number]}
}),
#"Expanded Data" = Table.ExpandTableColumn(#"Grouped Rows", "Data", {"Value"}, {"Data.Value"}),
#"Added Custom" = Table.AddColumn(#"Expanded Data", "Custom", each if [Data.Value] > [Avg] then [Data.Value] else null),
#"Grouped Rows1" = Table.Group(#"Added Custom", {"Date"}, {{"Avg Value", each List.Average([Custom]), type nullable number}})
in
#"Grouped Rows1"
Since you are using the Device ID column in the table, it shows all of them separately. Can you remove the DeviceID column and try the value column as average?

previous pay period using dax

I am very new to power bi and power query and while I have searched for a solution, I may be so new that I am unaware that a similar solution is here and could solve my issue but here goes.
I have been tasked with taking a table of data (which I don't have access to alter) and display in Power BI current pay period data along side data from the previous pay period (essentially doing an Excel vlookup for the previous period (each pay period is 14 days apart)) and then creating calculations to show the change in position vacancy from one pay period to the next. I only have Power Query and Power BI in which to make this happen. I created a key from different columns and then a linked a referenced table to pull the previous dates info but this didn't work once I started putting slicers on the matrix. Right now I'm trying to assign each pay period a identifier which grows by one with each later date (completed) and then create a column which reads the table and gives the previous pay period vacancy hours.
Empl Number
Sched Hours
Budg Hours
Vacant Hours
Pay Period
1
0.00
9.00
9.00
01/01/2022
2
22.5
22.5
0.00
01/01/2022
2
0.00
22.5
22.5
01/15/2022
3
0.00
37.5
37.5
01/01/2022
3
37.5
37.5
0.00
01/15/2022
3
37.5
37.5
0.00
01/29/2022
I am expecting to see something like the image below in Power BI:
Pay Period
Total Vacant Hours
Vacant Hour Change
01/01/2022
46.5
01/15/2022
60.0
13.5
01/29/2022
0.00
-60.0
02/12/2022
0.00
0.00
try to create a new table
Modelling --> New Table
previous pay period using dax = SUMMARIZE (
'Table',
'Table'[Pay Period],
"Sum Vacant", SUM ( 'Table'[Vacant Hours ] ),
"Balance Vacant",
SUM ( 'Table'[Vacant Hours ] )
- CALCULATE (
SUM ( 'Table'[Vacant Hours ] ),
FILTER (
ALL ( 'Table' ),
'Table'[Pay Period]
= CALCULATE (
MAX ( 'Table'[Pay Period] ),
FILTER (
ALL ( 'Table' ),
'Table'[Pay Period] < SELECTEDVALUE ( 'Table'[Pay Period] )
)
)
)
)
)
In Power Query: (Read the comments to understand the algorithm)
let
//Change next line to reflect your actual data source
Source = Excel.CurrentWorkbook(){[Name="Table8"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"Empl Number", Int64.Type}, {"Sched Hours", type number}, {"Budg Hours", type number},
{"Vacant Hours", type number}, {"Pay Period", type date}}),
//Group by pay period and aggregate Sum of Vacant Hours
#"Grouped Rows" = Table.Group(#"Changed Type", {"Pay Period"}, {
{"Vacant Hours", each List.Sum([Vacant Hours]), type nullable number}}),
//Add a column which is a "shifted" vacant hours column
// This will put this and previous pay period on same row
#"Shifted Vacant Hours" = Table.FromColumns(
Table.ToColumns(#"Grouped Rows") & {{null} & List.RemoveLastN(#"Grouped Rows"[Vacant Hours],1)},
type table[Pay Period=date, Total Vacant Hours=number, Shifted Vacant=number]),
//add a column subtracting Shifted Vacant from Total Vacant
#"Added Custom" = Table.AddColumn(#"Shifted Vacant Hours", "Vacant Hour Change", each if [Shifted Vacant] = null then null else
[Total Vacant Hours]-[Shifted Vacant]),
//Remove the Shifted Vacant column
#"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"Shifted Vacant"})
in
#"Removed Columns"
Edit for different grouping
If you want to have a table where the Vacant hour change is computed per employee (for each time period), then we would Group By: Empl Number, and write a custom aggregation to add the "Vacancy Change" column.
The code below assumes only a single entry per customer per pay period, as you show in your example. If there might be multiple entries per employee per pay period, minor code changes will be needed.
let
//Change next line to reflect your actual data source
Source = Excel.CurrentWorkbook(){[Name="Table8"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"Empl Number", Int64.Type}, {"Sched Hours", type number}, {"Budg Hours", type number},
{"Vacant Hours", type number}, {"Pay Period", type date}}),
//Group by pay period and custom aggregaton to assess by Employee for each time period
//Assumes only a single entry per employee per time period
#"Grouped Rows" = Table.Group(#"Changed Type", {"Empl Number"}, {
{"Calcs", (t)=> let
subTable = Table.FromColumns(
Table.ToColumns(t) & {{null} & List.RemoveLastN(t[Vacant Hours])},
{"Empl Number", "Sched Hours", "Budg Hours", "Vacant Hours", "Pay Period", "Shifted Vacant"}),
#"Vacancy Change" = Table.AddColumn(subTable,"Vacant Hour Change", each [Vacant Hours] - [Shifted Vacant]),
#"Remove Shifted" = Table.RemoveColumns(#"Vacancy Change",{"Shifted Vacant"})
in #"Remove Shifted",
type table[Empl Number=Int64.Type, Sched Hours=number, Budg Hours=number, Vacant Hours=number,
Pay Period=date, Vacant Hour Change=number]
}}),
//expand the table; set columns in proper order; remove unneeded columns
#"Expanded Calcs" = Table.ExpandTableColumn(#"Grouped Rows", "Calcs", {"Sched Hours", "Budg Hours", "Vacant Hours", "Pay Period", "Vacant Hour Change"}),
#"Reordered Columns" = Table.ReorderColumns(#"Expanded Calcs",{"Empl Number", "Pay Period", "Sched Hours", "Budg Hours", "Vacant Hours", "Vacant Hour Change"}),
#"Removed Columns" = Table.RemoveColumns(#"Reordered Columns",{"Sched Hours", "Budg Hours"})
in
#"Removed Columns"

In Dax, how can i count values in one column that equal the value of another column?

I have two columns, i want a table that shows the number of "Assign Date" in "Week Start" so for "Week Start" of 1/1/2022 it should be 0, for "Week Start" of 1/7/2022, it should be 2, and it should be 1 for 1/14/2022 and 1/21/2022.
I have two date column
Week Start
Assign Date
1/1/2022
1/8/2022
1/8/2022
1/8/2022
1/15/2022
1/15/2022
1/22/2022
1/22/2022
I want one date column and one count column
Week Start
Assign Count
1/1/2022
0
1/8/2022
2
1/15/2022
1
1/22/2022
1
I am very new to DAX and i assume that i am over complicating the solution but i can't figure out where to start. Because i am learning DAX, i would like to get this in a DAX measure.
Or this measure:
Assign Count :=
VAR ThisWeekStart =
MIN( Table1[Week Start] )
RETURN
0
+ COUNTROWS(
FILTER(
ALL( Table1 ),
Table1[Assign Date] = ThisWeekStart
)
)
which you can place in a visual together with the Week Start field.
There may be more efficient M-Code, but what I did here was
to use List.Accumulate to count the number of entries that were in the correct range: >=Week Start and <Week Start + 7 days
M Code
let
Source = Excel.CurrentWorkbook(){[Name="Table3"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Week Start", type date}, {"Assign Date", type date}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "Assign Count",
each List.Accumulate(
#"Changed Type"[Assign Date],
0,
(state, current)=>
if current >=[Week Start] and current < Date.AddDays([Week Start],7) then state +1 else state)),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"Assign Date"})
in
#"Removed Columns"

Overlapping periods value summary on chart in Power BI

I don't know what I'm looking for maybe that is why I can't find solution online.
Just trying to show a data on simple chart with time axis.
Example of data I have:
ID
StartTime
EndTime
Quantity
1
11:00:00
12:00:00
10
2
11:30:00
12:20:00
10
3
12:00:00
13:00:00
10
4
13:40:00
14:00:00
10
5
13:50:00
15:00:00
10
Now on chart I would like to show:
Axis
Value on Chart
11:00:00
10
11:15:00
10
11:30:00
20
11:45:00
20
12:00:00
20
12:15:00
20
12:30:00
10
12:45:00
10
...
...
So overlapping period values should show on chart as sum.
Axis interval 15 min is just for example, but if required it could be fixed to 10 or 15 minutes.
In PQ M code you could:
Create a list of ALL the 15 minute bins from the earliest Start to the Latest end
Create a list of the 15 minute bins for each row Start..End
Join the two with JoinType.FullOuter
Group by the bin, return the Sum for each interval and Sort
Source
M Code
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMlTSUTI0tDIwACIQ0wjBNFCK1YlWMoIoMEYoMEJVYIymzRjdBBOIqAlM1ARdgSlEgSlM1BRFQSwA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [ID = _t, StartTime = _t, EndTime = _t, Quantity = _t]),
//set data types
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"ID", Int64.Type}, {"StartTime", type time}, {"EndTime", type time}, {"Quantity", Int64.Type}}),
//create List of all 15 minute intervals from earliest Start time to latest End time
quarterHours = List.Times(
List.Min(#"Changed Type"[StartTime]),
Duration.TotalMinutes(
List.Max(#"Changed Type"[EndTime]) - List.Min(#"Changed Type"[StartTime]))/15,#duration(0,0,15,0)),
//compute a List of 15 minute bins for each row
// where Start Time is rounded down to the 15 minute interval; and End Time is rounded up to the 15 minute interval
#"Added Custom" = Table.AddColumn(#"Changed Type", "Time Bin",
each List.Transform(
{Number.RoundDown(Number.From([StartTime])*96,0)..Number.RoundUp(Number.From([EndTime])*96,0)-1},
each _/96)),
//expand the Time Bin list to one entry per 15 minute interval
//and set the data type
#"Expanded Custom" = Table.ExpandListColumn(#"Added Custom", "Time Bin"),
#"Changed Type1" = Table.TransformColumnTypes(#"Expanded Custom",{{"Time Bin", type time}}),
//Join the column that has ALL of the 15 minute bins (so as to account for those intervals with no entries
addAllTimes = Table.Join(#"Changed Type1","Time Bin",
Table.FromColumns({quarterHours},type table[Bin=Time.Type]),"Bin",JoinKind.FullOuter),
//Group by Bin and Sort by time
#"Grouped Rows" = Table.Group(addAllTimes, {"Bin"}, {{"Quantity", each List.Sum([Quantity]), type nullable number}}),
#"Sorted Rows" = Table.Sort(#"Grouped Rows",{{"Bin", Order.Ascending}})
in
#"Sorted Rows"
Results
Define a new table corresponding to the Axis column you show and then write a measure to use for the values along these lines:
ChartValue =
VAR CurrTime = SELECTEDVALUE ( NewTable[Axis] )
RETURN
CALCULATE (
SUM ( Data[Amount] ),
Data[StartTime] <= CurrTime,
Data[EndTime] >= CurrTime
)
In my example I put the data from your question into a table (insert > table) and named it tblData.
The axis-data are in table tblAxis, Quantity is calculated using the the SUMIFS-Formula which checks for Start and End-Time.
=SUMIFS(tblData[Quantity];tblData[StartTime];"<=" & [#Axis];tblData[EndTime];">" & [#Axis])
Thank you both.
Both solutions works!!
However for my limited knowledge, makes it easier for me to use ike solutions.

Power Query - COUNTIFS copycat with performance issue. Which is a better approach?

The scenario and data structure is very simple.
I have a list with the product code and the month that this product have been retailed. A example of such data can be seen at the first two columns in green at the image below.
Then I need to check for each product If it was retailed also on the last month, on the last 3 months or in the last 12 months. The result would be the next three columns in yellow on the image.
These calculations (yellow columns) are easy to be computed at Excel by using some IF and COUNTIFS formulas, but when migrating it to Power BI I'm struggling with the performance of my code at Power Query. As there are thousands of products for each month, the Power Query calculation is taking too long.
Check below the code I've designed. The code snapshot would be for the second yellow column, to advise whether there was a retail on the last 3 months or not of that product.
In essence what I'm doing is adding a calculated column that is counting the rows of a table that is being filtered with the product code information and relevant date.
What would be a better approach in terms of performance to get the information I need?
Thank you.
Code:
// Add a calculated column.
AdicionarHits03Meses = Table.AddColumn(
AdicionarHits01Mes,
"Hit nos Ășltimos 3 meses?",
(r)=>
// Check if...
if
// Returns the rows count of a table.
Table.RowCount(
// Returns a table with the condition.
Table.SelectRows(
ChangeType,
// Condition:
(q)=>
// Same Product Code.
q[#"Product Code"] = r[#"Product Code"]
and
// Check the retail month.
q[#"Retail month"] <= Date.AddMonths(r[#"Retail month"], -1) and
q[#"Retail month"] >= Date.AddMonths(r[#"Retail month"], -3)
)
)
= 0 then
// No retail found.
0 else
// Retail found.
1
,
Int64.Type
)
You can likely improve performance with some clever self-merges.
See if this makes sense to you:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMlTSUfJKzFMwMjAyVIrViVYyQhcwRhcAaXFLTUIV8E0sQjXDN7ESzdDSHKhALAA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Product Code" = _t, #"Retail Month" = _t]),
Original = Table.TransformColumnTypes(Source,{{"Product Code", Int64.Type}, {"Retail Month", type date}}),
#"Added Offset Lists" = Table.AddColumn(Original, "Offset", each {1..12}),
#"Expanded Offset Column" = Table.ExpandListColumn(#"Added Offset Lists", "Offset"),
#"Added Prev Column" = Table.AddColumn(#"Expanded Offset Column", "Prev", each Date.AddMonths([Retail Month], -[Offset] ), type date),
#"Inner Join Prev to Original" = Table.NestedJoin(#"Added Prev Column", {"Product Code", "Prev"}, Original, {"Product Code", "Retail Month"}, "Retail", JoinKind.Inner),
#"Merge Original to Prev" = Table.NestedJoin(Original, {"Product Code", "Retail Month"}, #"Inner Join Prev to Original", {"Product Code", "Retail Month"}, "Min Offset", JoinKind.LeftOuter),
#"Expanded Min Offset" = Table.TransformColumns(#"Merge Original to Prev", {{"Min Offset", each List.Min([Offset]), Int64.Type}}),
#"Added Last Month" = Table.AddColumn(#"Expanded Min Offset", "Retail last month", each if [Min Offset] = 1 then "Yes" else "No", type text),
#"Added Last 3 Months" = Table.AddColumn(#"Added Last Month", "Retailed since last 3 months", each if [Min Offset] <> null and [Min Offset] <= 3 then "Yes" else "No", type text),
#"Added Last 12 Months" = Table.AddColumn(#"Added Last 3 Months", "Retailed since 12 months", each if [Min Offset] <> null and [Min Offset] <= 12 then "Yes" else "No", type text)
in
#"Added Last 12 Months"
I don't have time to fully explain it but the outline is roughly as follows:
Expand each row to 12 rows of prior months.
Match up those prior months with rows from the original table.
Join the original rows with all of the matches found for that row.
Find the most recent match (minimal offset) for each matching set.
Define the 1, 3, and 12-month lookback columns using this offset.