increase date column based on conditions - powerbi

I am having some issues with how to approach my query so any help would be greatly appreciated.
I have a date column that I need to increase based on two other columns values.
e.g. Date Reported column - 17/12/2018
If my Impact Column = "Urgent" and my Department = "Stores" I would need to increase my Date Reported Column to 18/12/2018
However if my Impact Column = "Standard" and my Department = "Floor" I would need to increase my Date Reported Column to 20/12/208
I would ideally like to not touch the original Date Reported Column but move this new value to another column.
So Far I have created a custom column and this is my code however it doesnt work.
AmendedDateReported = if(And(SurveyCorrectiveAction[Impact] = "Urgent", SurveyCorrectiveAction[LookUp] = "Stores"), Date.AddDays([DateReported],1),Blank ())
Thanks
Paula
Updated code, The formula seems to be pulling ok but the date part wont update:
#"Sorted Rows" = Table.Sort(Source,{{"DateReported", Order.Ascending}}),
#"Changed Type" = Table.TransformColumnTypes(#"Sorted Rows",{{"DateReported", type date}}),
#"Sorted Rows1" = Table.Sort(#"Changed Type",{{"DateReported", Order.Descending}}),
#"Added Custom" = Table.AddColumn(#"Sorted Rows1", "Date Repaired", each ""),
#"Changed Type1" = Table.TransformColumnTypes(#"Added Custom",{{"Date Repaired", type text}}),
#"Duplicated Column" = Table.DuplicateColumn(#"Changed Type1", "DateReported", "DateReported - Copy"),
#"Renamed Columns" = Table.RenameColumns(#"Duplicated Column",{{"DateReported - Copy", "AmendedDateReported"}}),
#"Merged Amendments" = Table.NestedJoin(#"Renamed Columns",{"Impact", "Department"},TLU_FaultTimeScales,{"Impact", "Department"},"TLU_FaultTimeScales",JoinKind.LeftOuter),
#"Expanded Amendments" = Table.ExpandTableColumn(#"Merged Amendments", "TLU_FaultTimeScales", {"Amendment Day"}, {"Amendment Day"}),
AmendedDateReported = Table.AddColumn(#"Expanded Amendments", "AmendedDateReported", each try Date.AddDays([DateReported],[Amendment Day]) otherwise [DateReported], type date)
in
#"Renamed Columns"

You could try:
AmendedDateReported =
Table.AddColumn(
#"Previous Step",
"Amended Date Reported",
each Date.AddDays(
[Date Reported],
if [Impact] = "Urgent" and [Department] = "Stores" then 1
else if [Impact] = "Standard" and [Department] = "Floor" then 3
else 0
),
type date
)
If you have several combinations of Impact / Department which have variable effect on amending the date, it would make more sense to put those in a separate table:
+----------+------------+----------------+
| Impact | Department | Amendment Days |
+----------+------------+----------------+
| Urgent | Stores | 1 |
| Standard | Floor | 3 |
+----------+------------+----------------+
You can then join this table to retrieve the amendment days:
#"Merged Amendments" = Table.NestedJoin(#"Previous Step",{"Impact", "Department"},tblAmendments,{"Impact", "Department"},"tblAmendments",JoinKind.LeftOuter),
#"Expanded Amendments" = Table.ExpandTableColumn(#"Merged Amendments", "tblAmendments", {"Amendment Days"}, {"Amendment Days"}),
AmendedDateReported = Table.AddColumn(#"Expanded Amendments", "Amended Date Reported", each try Date.AddDays([Date Reported],[Amendment Days]) otherwise [Date Reported], type date)
in
AmendedDateReported
Remember to update the final variable name after the in clause.

Related

Power Query: Unpivoting Multiple different Attributes at the same time

In Power BI's Power Query, let say I have the below table.
Customer
Product 1: Type
Product 1: Cost
Product 2: Type
Product 2: Cost
Cust 1
A
$5
B
$15
Cust 2
A
$5
C
$20
The goal is to unpivot so that there is no product 1 or product 2, just product, effectively taking the 4 columns in to 2
Customer
Product Type
Product Cost
Cust 1
A
$5
Cust 1
B
$15
Cust 2
A
$5
Cust 2
C
$20
I know this is fairly simple if just unpivoting from many columns to 1 column through the Unpivot columns function.
But how do you go about unpivoting many columns into n columns without doing this n times and rejoining?
You can unpivot all columns except Customer, split the Attribute values into Product and Header, then re-pivot:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wci4tLlEwVNJRcgRiFVMg4QRiGJoqxepAZY2QZZ1BDCMDpdhYAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Customer = _t, #"Product 1: Type" = _t, #"Product 1: Cost" = _t, #"Product 2: Type" = _t, #"Product 2: Cost" = _t]),
Unpivoted = Table.UnpivotOtherColumns(Source, {"Customer"}, "Attribute", "Value"),
#"Split Attribute" = Table.SplitColumn(Unpivoted, "Attribute", Splitter.SplitTextByEachDelimiter({": "}, QuoteStyle.Csv, false), {"Product", "Header"}),
#"Pivoted Column" = Table.Pivot(#"Split Attribute", List.Distinct(#"Split Attribute"[Header]), "Header", "Value"),
#"Removed Columns" = Table.RemoveColumns(#"Pivoted Column",{"Product"})
in
#"Removed Columns"
Which turns
into
This should work also
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
base_columns=1, groupsof=2, // stack them
Combo = List.Transform(List.Split(List.Skip(Table.ColumnNames(Source),base_columns),groupsof), each List.FirstN(Table.ColumnNames(Source),base_columns) & _),
#"Added Custom" =List.Accumulate(
Combo,
#table({"Column1"}, {}),
(state,current)=> state & Table.Skip(Table.DemoteHeaders(Table.SelectColumns(Source, current)),1))
in #"Added Custom"

Repeat the last value over time

I have a table with power plant capacities in different years. There are only entries when something changes in the capacities. In the years not listed, the last value applies.
Plant
Year
Capacity
Cottam
2003
800
Cottam
2009
600
Cottam
2015
800
Drax
2000
600
Drax
2005
1200
Drax
2010
1800
Drax
2013
1200
Drax
2020
0
Ironbridge
2007
500
Ironbridge
2015
0
Now I would like to transform the initial table, so that I also have values for all years in between and can display them in a stacked column chart, for example. The result should look like shown in the table below. Marked in yellow are the numbers from the initial table.
You can do this easily in the Query Editor in M code.
To reproduce, paste the code below into a blank query:
let
//change next line to reflect your actual data source
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wcs4vKUnMVdJRMjIwMAZSFgYGSrE6qOKWQMoMU9zQFEm9S1FiBUS1AZJqhChIraERurAhSLEhhhmGxlhVG4FUQ8Q8i/LzkooyU9JTIcabAylTA6xyYGcCZWIB", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Plant = _t, Year = _t, Capacity = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Plant", type text}, {"Year", Int64.Type}, {"Capacity", Int64.Type}}),
//generate Table of all years
#"All Years" = Table.FromColumns(
{List.Numbers(List.Min(#"Changed Type"[Year]), List.Max(#"Changed Type"[Year])- List.Min(#"Changed Type"[Year]) + 1 )}),
//Group by Plant
// Aggregate by joining with the All Years table and "Fill Down" to replace blanks with previous year.
// then expand the grouped column
#"Group by Plant" = Table.Group(#"Changed Type","Plant",{
{"Joined", each Table.FillDown(Table.Join(#"All Years","Column1",_,"Year",JoinKind.FullOuter),{"Capacity"})}
}),
#"Expanded Joined" = Table.ExpandTableColumn(#"Group by Plant", "Joined", {"Column1", "Capacity"}, {"Column1", "Capacity"}),
//Replace nulls with zero's
#"Replaced Value" = Table.ReplaceValue(#"Expanded Joined",null,0,Replacer.ReplaceValue,{"Capacity"}),
//Pivot on year
// then set the data types
#"Pivoted Column" = Table.Pivot(Table.TransformColumnTypes(#"Replaced Value", {{"Column1", type text}}, "en-US"),
List.Distinct(Table.TransformColumnTypes(#"Replaced Value", {{"Column1", type text}}, "en-US")[Column1]), "Column1", "Capacity"),
//set data type
#"Changed Type1" = Table.TransformColumnTypes(#"Pivoted Column",
List.Transform(List.Sort(List.RemoveFirstN(Table.ColumnNames(#"Pivoted Column"),1), Order.Ascending), each {_, Int64.Type}))
in
#"Changed Type1"
Edit Note:
Actually, to create the graph in Power BI, you do NOT want to pivot the data, so the shorter code:
let
//change next line to reflect your actual data source
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wcs4vKUnMVdJRMjIwMAZSFgYGSrE6qOKWQMoMU9zQFEm9S1FiBUS1AZJqhChIraERurAhSLEhhhmGxlhVG4FUQ8Q8i/LzkooyU9JTIcabAylTA6xyYGcCZWIB", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Plant = _t, Year = _t, Capacity = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Plant", type text}, {"Year", Int64.Type}, {"Capacity", Int64.Type}}),
//generate Table of all years
#"All Years" = Table.FromColumns(
{List.Numbers(List.Min(#"Changed Type"[Year]), List.Max(#"Changed Type"[Year])- List.Min(#"Changed Type"[Year]) + 1 )}),
//Group by Plant
// Aggregate by joining with the All Years table and "Fill Down" to replace blanks with previous year.
// then expand the grouped column
#"Group by Plant" = Table.Group(#"Changed Type","Plant",{
{"Joined", each Table.FillDown(Table.Join(#"All Years","Column1",_,"Year",JoinKind.FullOuter),{"Capacity"})}
}),
#"Expanded Joined" = Table.ExpandTableColumn(#"Group by Plant", "Joined", {"Column1", "Capacity"}, {"Year", "Capacity"}),
//Replace nulls with zero's
#"Replaced Value" = Table.ReplaceValue(#"Expanded Joined",null,0,Replacer.ReplaceValue,{"Capacity"}),
#"Changed Type1" = Table.TransformColumnTypes(#"Replaced Value",{{"Year", Int64.Type}, {"Capacity", Int64.Type}})
in
#"Changed Type1"
Then, in Power BI, you can generate this:
Note:
The code below presents the Table FillDown / Table Join sequence from the first code using variables and more comments. Should be easier to understand (might be less efficient, though)
...
{"Joined", each
let
//join the subtable with the All Years table
#"Joined Table" = Table.Join(#"All Years", "Column1", _, "Year", JoinKind.FullOuter),
//Fill down the Capacity column so as to fill with the "last year" data
// since that column will contain a null after the Table.Join for years with no data
#"Fill Down" = Table.FillDown(#"Joined Table",{"Capacity"})
in
#"Fill Down"
}
...
Here's how to solve this (more easily) in DAX:
Prerequisite is separate Calendar table with a 1:many relation on the year
Calendar =
SELECTCOLUMNS(
GENERATESERIES(
MIN(Plants[Year]),
MAX(Plants[Year])
),
"Year", [Value]
)
Next calculate the Last Given Capacity per year
Last Given Capacity =
VAR current_year =
MAX(Calendar[Year])
VAR last_capacity_year =
CALCULATE(
MAX(Plants[Year]),
'Calendar'[Year] <= current_year
)
RETURN
CALCULATE(
MAX(Plants[Capacity]),
Calendar[Year] = last_capacity_year
)
Finally put it all together in a Stacked Column Chart with
X-axis: 'Calendar'[Year]
Y-axis: [Last Given Capacity]
Legend: 'Plants'[Plant]

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

QoQ Calculation Power BI

I'm calculating QoQ Imp and QoQ %Eng in the below data table which is grouped by with the help of power query by adding "Index starting from 0" and "Index.1 starting from 1".
I have a "filter" column in the Filters pane this visual. Please help me in calculating QoQ Imp and QoQ %Eng in the above Table A. The expected result/output should look like this below table:-
In Power Query (M Code), assuming your data is representative, you can compute the QoQ values before filtering/grouping etc.
Add your Index column as you show
Then add a Modulo column (value = 4, since you have four quarters)
Then add custom columns for your two calculations:
Then filter as needed
Here is the M Code assuming the data source is an Excel Table. Modify the Source line as needed
let
Source = Excel.CurrentWorkbook(){[Name="Table7"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Qtr", type text}, {"Filter", type text}, {"Imp", Int64.Type}, {"Eng", Int64.Type}}),
//Compute % Eng column
#"Added Custom" = Table.AddColumn(#"Changed Type", "% Eng", each [Eng]/[Imp], Percentage.Type),
//Add Index and Modulo columns
#"Added Index" = Table.AddIndexColumn(#"Added Custom", "Index", 0, 1, Int64.Type),
#"Inserted Modulo" = Table.AddColumn(#"Added Index", "Modulo", each Number.Mod([Index], 4), type number),
//Compute QOQs -- (current row - previous row)/previous row (unless first row in the group in which case => null
#"Added Custom1" = Table.AddColumn(#"Inserted Modulo", "QoQ Imp", each if [Modulo]=0 then null
else ([Imp] - #"Inserted Modulo"[Imp]{[Index]-1}) / #"Inserted Modulo"[Imp]{[Index]-1}),
#"Added Custom2" = Table.AddColumn(#"Added Custom1", "QoQ %Eng", each if [Modulo]=0 then null
else ([#"% Eng"] - #"Inserted Modulo"[#"% Eng"]{[Index]-1}) / #"Inserted Modulo"[#"% Eng"]{[Index]-1}),
//remove now superfluous Index and Modulo columns and re-order the others
#"Removed Columns" = Table.RemoveColumns(#"Added Custom2",{"Index", "Modulo"}),
#"Reordered Columns" = Table.ReorderColumns(#"Removed Columns",{"Qtr", "Filter", "Imp", "QoQ Imp", "Eng", "% Eng", "QoQ %Eng"})
in
#"Reordered Columns"

Add missing date rows in Power BI/Power Query and take value of row above

Say I am importing something like the following into PowerBI:
Date | Quantity
|---------------------|------------------|
| 1/1/2018 | 22 |
| 1/3/2018 | 30 |
| 1/4/2018 | 10 |
|---------------------|------------------|
Where the external source table is a series of date, value rows with some date values missing. I'd like to execute some DAX/M to add any missing date rows into the data set, where 'Quantity' value is taken from the first date prior. So my resulting dataset would like like this:
Date | Quantity
|---------------------|------------------|
| 1/1/2018 | 22 |
| 1/2/2018 | 22 |
| 1/3/2018 | 30 |
| 1/4/2018 | 10 |
|---------------------|------------------|
Can this be done in PowerBI?
Help is much appreciated!
You can do this in DAX by creating a new table with all of the dates in your range as follows:
FullTable =
ADDCOLUMNS(
CALENDAR(MIN(Table1[Date]), MAX(Table1[Date])),
"Quantity",
LOOKUPVALUE(
Table1[Quantity],
Table1[Date],
MAXX(
FILTER(Table1, Table1[Date] <= EARLIER([Date])),
[Date]
)
)
)
The CALENDAR function gives you a range of dates from you minimum to maximum dates in your original table. From there, we add a new column, Quantity, and define it as the value we get when looking up the Quantity in the original table for the date that was the maximum date occurring on or before the date in the current row.
In Power Query "M" code, see the comments to understand the different steps. Basically, it generates a new table with all the days, takes the Quantity values if avaliable and fill down the gaps.
Hope this help you.
let
Source = Excel.CurrentWorkbook(){[Name="Test"]}[Content],
Converted = Table.TransformColumnTypes(Source,{{"Date", type date}}),
// force conversion to date type to avoid problems if date values comes from an Excel table (in Excel they are numbers).
DatesCol = Converted[Date],
// list from Date column of Converted table
Ini = List.Min(DatesCol),
End = List.Max(DatesCol),
Size = Number.From(End - Ini) +1,
DatesNew = List.Dates(Ini, Size, #duration(1, 0, 0, 0)),
// generates a new list of dates from min to max
NewTable = Table.FromColumns({DatesNew},{"Dates"}),
// new table from new list of dates, column name is "Dates" not "Date".
Joined = Table.Join(NewTable,"Dates",Converted,"Date",JoinKind.FullOuter),
// join both table NewTable and Converted (from Source) and keep all the dates from the DatesNew list.
Removed = Table.RemoveColumns(Joined, "Date"),
// remove the original Date column as it's not needed.
Result = Table.FillDown(Removed,{"Quantity"})
// Fill Down the Quantity column.
in
Result
Two items below should do it
// Query name fnGeT
(TableName as table, DateSearch as date) =>
let Source2 = Table.SelectRows(TableName, each [Date] < DateSearch and [quantity] <> null),
Max= Table.Group(Source2, {}, {{"Max", each List.Max([Date]), type date}}),
MaxDate = Table.SelectRows(Source2, each [Date] = Max{0}[Max]),
Value = MaxDate{0}[quantity]
in Value
and
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Base = Table.TransformColumnTypes(Source,{{"Date", type date}, {"quantity", Int64.Type}}),
// Generate list of dates between Max and Min dates of Table1
DateRange = Table.Group(Base, {}, {{"MinDate", each List.Min([Date]), type date}, {"MaxDate", each List.Max([Date]), type date}}),
StartDate = DateRange[MinDate]{0},
EndDate = DateRange[MaxDate]{0},
List ={Number.From(StartDate)..Number.From(EndDate)},
#"Converted to Table" = Table.FromList(List, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
FullList = Table.TransformColumnTypes(#"Converted to Table",{{"Column1", type date}}),
//Right Anti Join to find dates not in original Table1
#"Merged Queries" = Table.NestedJoin(Base,{"Date"},FullList,{"Column1"},"Table2",JoinKind.RightAnti),
#"Removed Other Columns" = Table.SelectColumns(#"Merged Queries",{"Table2"}),
Extras = Table.ExpandTableColumn(#"Removed Other Columns", "Table2", {"Column1"}, {"Date"}),
Combined = Base & Extras,
#"Added Custom" = Table.AddColumn(Combined, "Custom", each if [quantity]<>null then [quantity] else fnGet(Combined,[Date])),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"quantity"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Custom", "quantity"}})
in #"Renamed Columns"