Assign value of another table according to multiple conditions - powerbi

I have two separate tables, without an existing relationship, similar to the ones below.
What I am trying to do is to multiply the SalesAmount by the respective Royalty slot, according to the following conditions.
Sales[Store] = Royalties[Store]
Sales[Year] = Royalties[Year]
Sales[Category] = Royalties[Category]
And then slot assignment according to this logic
SALES SalesAmount = 160
ROYALTIES
Slot 1 -- from 0 to 100 -- 5%.
Slot 2 -- from 100 to 200 -- 10%.
Then the value of royalties should be:
Slot 1 = 100 * 5% = 5
Slot 2 = 60 * 10% = 6
Royalties value = 5 +6 = 11
Tab. SALES
Store
Year
Category
SalesAmount
A
2022
X
250
B
2022
Y
260
Tab. ROYALTIES
INDEX
Store
Year
Category
n_slot
initial_value
final_value
royalties_pct
1
A
2022
X
1
0
100
5%
2
A
2022
X
2
100
200
7%
3
A
2022
X
3
200
300
9%
4
B
2022
Y
1
0
80
4%
5
B
2022
Y
2
80
160
6%
6
B
2022
Y
3
160
240
8%
How can I fix this to get the correct result?

If you feel like doing it in M / Powerquery
Code for SALES query
let Source = Excel.CurrentWorkbook(){[Name="SALESTABLE"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Store", type text}, {"Year", Int64.Type}, {"Category", type text}, {"SalesAmount", Int64.Type}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "Royalty", each GetRoyalties([Store],[Year],[Category],[SalesAmount]))
in #"Added Custom"
Code for function GetRoyalties which pulls from query ROYALTIES
( xStore as text, xYear as number, xCategory as text, xValue as number) as number =>
let #"Filtered Rows" = Table.SelectRows(ROYALTIES, each [Store] = xStore and [Year] = xYear and [Category] = xCategory),
#"Added Custom" = Table.AddColumn(#"Filtered Rows", "Custom", each if xValue>[final_value] then [royalties_pct]*([final_value]-[initial_value]) else if xValue<[initial_value] then 0 else (xValue-[initial_value])*[royalties_pct]),
Total = List.Sum(#"Added Custom"[Custom])
in Total

Related

How to convert decimal date type column to time data type in power query/power BI?

The column consist of minutes that is in the decimal format. This is to be converted to Time format.
Example: The 5th record is 61 minutes and 6 seconds.
This is to be displayed as 1 hour, 1 minute and 6 seconds - (01:01:06).
How to solve this problem in power query editor/ power BI?
Plenty of options. You can do it in Power Query, in DAX as a measure or as a calculated column.
Here is a simple calculated column:
Formatted =
VAR _hrs = QUOTIENT ( [minutes_watched] , 60 )
VAR _mins = INT ( [minutes_watched] - _hrs * 60 )
VAR _sec = MOD ( [minutes_watched] , 1.0 ) * 60
RETURN
FORMAT(_hrs,"00")&":"&FORMAT(_mins,"00")&":"&FORMAT(_sec,"00")
This also handles weirdos watching for more than 24 hrs, at which a TIME data type would overflow:
It is also easily written as a measure where the minutes watched can be an aggregation instead:
Formatted Minutes :=
VAR _agg_time = [Sum minutes watched] // Aggregation measure of choice goes here
VAR _hrs = QUOTIENT ( _agg_time , 60 )
VAR _mins = INT ( _agg_time - _hrs * 60 )
VAR _sec = MOD ( _agg_time , 1.0 ) * 60
RETURN
FORMAT(_hrs,"00")&":"&FORMAT(_mins,"00")&":"&FORMAT(_sec,"00")
Which gives you this result:
Simply divide your minutes decimal by (24 * 60) and you can convert it into Time format:
let
Source = Table.FromList({"0.3", "2.7", "46.8", "61.6"}),
#"Renamed Columns" = Table.RenameColumns(
Source,{{"Column1", "minutes_watched"}}),
#"Changed Type" = Table.TransformColumnTypes(
#"Renamed Columns",{{"minutes_watched", type number}}),
#"Added Custom" = Table.AddColumn(
#"Changed Type", "Custom", each [minutes_watched] / 60 / 24),
#"Changed Type1" = Table.TransformColumnTypes(
#"Added Custom",{{"Custom", type time}})
in
#"Changed Type1"
Add column ... custom column.. with formula
= #duration(0,0,Number.From(Text.Split(Text.From([minutes_watched]),"."){0}),Number.From(Text.Split(Text.From([minutes_watched]),"."){1}))

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"

Calculate working and non working Hrs of a device in particular day based on its ignition status

I am trying to calculate, working hours of forklifts on a particular day based on their ON/OFF ignition status.
My code is perfectly working fine when I ignore the condition were either ON or OFF are missing.
Requirement:
Need to handle boudary conditions were last entry of the day for a device is ON
or you can say , if last entry off a day is ON, then we need to calculate its working hrs. till 12 PM midnight.And subsequently add working hrs. in next day as well
Dataset :
DEVICEID : DATETIME: IGNITIONSTATUS
1 1/11/2020 8:00 ON
1 1/11/2020 14:00 OFF
2 10/28/2020 7:54 ON
2 10/28/2020 12:23 OFF
2 10/28/2020 14:01:44 PM ON
2 10/29/2020 20:01 ON
2 10/29/2020 14:01:44 PM OFF
1 12/10/2020 8:27 ON
1 12/10/2020 15:44:22 PM OFF
let
Source = Excel.Workbook(File.Contents("C:\Users\avyas2\Desktop\DataToTest.xlsx"), null, true),
Sheet1_Sheet = Source{[Item="Sheet1",Kind="Sheet"]}[Data],
#"Promoted Headers" = Table.PromoteHeaders(Sheet1_Sheet, [PromoteAllScalars=true]),
#"Changed Type" = Table.TransformColumnTypes(#"Promoted Headers",{{"DEVICEID", Int64.Type}, {"DATETIME", type datetime}, {"IGNITIONSTATUS", type text}}),
#"Split DateTime" = Table.SplitColumn(#"Changed Type", "DATETIME", (dt) => {DateTime.Date(dt), DateTime.Time(dt)}, {"Date", "Time"}),
#"Group by Date" = Table.Group(#"Split DateTime", {"DEVICEID", "Date"}, {{
"AvailabilityStatus",
each
let
times = _[[Time], [IGNITIONSTATUS]],
ins = List.Sort(Table.SelectRows(times, each [IGNITIONSTATUS] = "ON")[Time]),
outs = List.Sort(Table.SelectRows(times, each [IGNITIONSTATUS] = "OFF")[Time]),
zip = List.Select(List.Zip({ins, outs}), each _{0} <> null and _{1} <> null )
in
zip
, type {{time}}
}}),
#"Split AvailabilityStatus" = Table.SplitColumn(Table.ExpandListColumn(#"Group by Date", "AvailabilityStatus"), "AvailabilityStatus", (x) => x, {"ON", "OFF"}),
#"Added Worked Time" = Table.AddColumn(#"Split AvailabilityStatus", "Hours Worked", each Duration.TotalHours([OFF] - [ON]), type number),
#"Renamed Columns" = Table.RenameColumns(#"Added Worked Time",{{"Hours Worked", "WorkingHrs"}})
in
#"Renamed Columns"
Maybe You need only a DAX measure?
WorkingHour =
var _thisLine = SELECTEDVALUE(Sheet2[DATETIME] )
var result = if(SELECTEDVALUE(Sheet2[IGNITIONSTATUS] )="ON",
var minDate = CALCULATE( min(Sheet2[DATETIME]), filter(ALL(Sheet2), Sheet2[DEVICEID] = SELECTEDVALUE(Sheet2[DEVICEID] ) && Sheet2[DATETIME] > _thisLine && Sheet2[IGNITIONSTATUS] ="OFF"
&& DATE(YEAR(Sheet2[DATETIME]),MONTH(Sheet2[DATETIME]),DAY(Sheet2[DATETIME])) = DATE(YEAR(_thisLine),MONTH(_thisLine),DAY(_thisLine))
))
return
if( ISBLANK(minDate),DATE(YEAR(_thisLine),MONTH(_thisLine),DAY(_thisLine)) +1 ,minDate) - _thisLine
)
return
result

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.

Calculated columns bases on the past 3 months in Power query

First time trying to use M in power query... what I have is this table
I need to create two columns that per each row (combination of CD_Loja x CD_Produto )returns me the sum of QT_VENDA for that combination divided by the # of days in the past 3 months. The other column is pretty much the same but with the sum of  VL_VENDA_LIQ  Instead.
I.e: For the first row I want to sum up all QT_VENDA that matches CD_PRODUTO =1001930 AND CD_LOJA = 151 in the past 3 months (the DATE column has daily data) and divide it by the number of days in those 3 months.
Is there a way to do so ? And how do I go about this ?
Thanks in advance.
In powerquery, M, something along these lines
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.Buffer(Table.TransformColumnTypes(Source,{{"DATA", type date}, {"CD_PRODUCTO", type text}, {"CD_LOIA", type text}, {"QT_VENDA", Int64.Type}, {"VL_VENDA_LIQ", Int64.Type}})),
#"Added Custom" = Table.AddColumn(#"Changed Type" ,"QT_VENDA_90",(i)=>List.Average(Table.SelectRows(#"Changed Type" , each [CD_PRODUCTO]=i[CD_PRODUCTO] and [CD_LOIA]=i[CD_LOIA] and [DATA] <= i[DATA] and [DATA] >= Date.AddDays(i[DATA] ,-90)) [QT_VENDA]), type number),
#"Added Custom2" = Table.AddColumn(#"Added Custom" ,"VL_VENDA_LIQ_90",(i)=>List.Average(Table.SelectRows(#"Changed Type" , each [CD_PRODUCTO]=i[CD_PRODUCTO] and [CD_LOIA]=i[CD_LOIA] and [DATA] <= i[DATA] and [DATA] >= Date.AddDays(i[DATA] ,-90)) [VL_VENDA_LIQ]), type number)
in #"Added Custom2"
You can try a Measure like below-
your_expected_value =
var current_row_data = MIN(your_table_name[DATA])
--I Guess the column name should be Date instead
var current_row_data_minus_90_day = MIN(your_table_name[DATA]) - 90
var current_row_cd_produto = MIN(your_table_name[CD_PRODUTO])
var current_row_cd_loja = MIN(your_table_name[CD_LOJA])
RETURN
CALCULATE(
SUM(your_table_name[QT_VENDA]),
FILTER(
ALL(your_table_name),
your_table_name[DATA] >= current_row_data_minus_90_day
&& your_table_name[DATA] <= current_row_data
&& your_table_name[CD_PRODUTO] = current_row_cd_produto
&& your_table_name[CD_LOJA] = current_row_cd_loja
)
)/90
--Here 90 used for static 3 month consideration