I have a data set containing:
Accounts selling various fruits in various countries, im working on some metrics and I really want to calculate the time between the first sold fruit in a country to the last sold fruit in the same country.
For instance: "days between" First sold ORANGE in Austria to Last sold ORANGE in AUSTRIA
I have solved this using a measure, which works but this doesn't allow me to work further with it as it throws me error with circular dependicies (ALL reference!)
I wonder if I can do this less complicated? an idea would be to set up an additional table in powerquery having latest date sold by fruit and country similar to what a pivot can do in excel, after that I could link to my main table and retrieve the date by using the RELATED option.
Any ideas?
Current muesure in powerBI:
DURATION =
VAR dispdate =
MIN( 'Test dat'[Dispath] )
VAR lastsoldthiscountry =
CALCULATE(
MAX( 'Test dat'[Last sold date] ),
ALL( 'Test dat' ),
SUMMARIZE( 'Test dat', 'Test dat'[Fruit], 'Test dat'[Country] )
)
RETURN
IF(
NOT ( ISBLANK( lastsoldthiscountry ) ) && NOT ( ISBLANK(dispdate) ),
INT( lastsoldthiscountry - dispdate )
)
Excel raw test:
https://www.dropbox.com/scl/fi/cppyzagm4ahusrxmadlg6/Test_data_withPivot.xlsx?dl=0&rlkey=2nf5wzl7etwr2hqg2lh4oyifx
PBI file:
https://www.dropbox.com/s/ljnyics6d7n74oc/test.pbix?dl=0
If I understand you correctly, you can do what you want entirely in Power Query.
Group by Fruit and Country
Aggregate by Min of Start Date and Max of End Date
Add column to calculate the Days difference:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"Fruit", type text}, {"Account ID", type text}, {"Country", type text},
{"Sold amount", Int64.Type}, {"Dispath", type date}, {"First sold date", type date}, {"Last sold date", type date}}),
#"Grouped Rows" = Table.Group(#"Changed Type", {"Fruit", "Country"}, {
{"First Date Sold", each List.Min([First sold date]), type nullable date},
{"Last Date Sold", each List.Max([Last sold date]), type nullable date}}),
#"Sorted Rows" = Table.Sort(#"Grouped Rows",{{"Fruit", Order.Ascending}, {"Country", Order.Ascending}}),
#"Added Custom" = Table.AddColumn(#"Sorted Rows", "Days Sold", each
Duration.Days([Last Date Sold]-[First Date Sold]),Int64.Type)
in
#"Added Custom"
The negative number for France Apples seems due to a data entry error
If there is a missing date entry, the table will show a null, due to how PQ processes nulls in arithmetical operations
Related
I'm working on a staff absence dashboard.
I'd like to know how many staff absences we have on a given day, based on the data below. I would like to be able to create a table of each day, which counts the number of absences on that day. The absence needs to count on the date, which could fall on the start date, end date or in between those.
Full Name Start Date End Date
----------------------------------
Employee D 03/11/2022 05/11/2022
Employee E 03/11/2022 04/11/2022
Employee A 04/11/2022 04/11/2022
Employee B 04/11/2022 06/11/2022
Employee C 04/11/2022 04/11/2022
Employee B 05/11/2022 06/11/2022
Based on the above table, I would expect the following:
Date Count
----------------
03/11/2022 2
04/11/2022 5
05/11/2022 3
06/11/2022 2
I use this formula but the end result isn't counting properly. Could someone help me with the formula?
Count per day = COUNTROWS(FILTER('Staff absence', 'Staff absence'[Absence Start Date]= MIN('Attendance Dates'[Date]) && 'Staff absence'[Absence End Date] >= MAX('Attendance Dates'[Date])))
Best to fix this in your data model. In Power Query join the Absences to the Date table, to create a table with one row for each employee for each day they are absent. Then you can simply count the rows in this table for a given day.
Here's an example:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wcs0tyMmvTE1VcFHSUTIw1jc01DcyMDICcUzhnFgdJIWuGApNsCt0RJUDc4yMoApjAQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Full Name" = _t, #"Start Date" = _t, #"End Date" = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Full Name", type text}, {"Start Date", type date}, {"End Date", type date}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "Days", each List.Dates([Start Date], 1+Number.From([End Date]-[Start Date]), #duration(1, 0, 0, 0))),
#"Expanded Days" = Table.ExpandListColumn(#"Added Custom", "Days"),
#"Renamed Columns" = Table.RenameColumns(#"Expanded Days",{{"Days", "Day Absent"}}),
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns",{"Start Date", "End Date"})
in
#"Removed Columns"
I've a table sales
idcustomer year of birth amount salesdate
112 1970 200 12/02/2022
12 1980 400 12/03/2012
122 1990 600 12/04/2012
300 1977 20 12/06/2012
500 1996 250 12/04/2012
I need to see how different agegroups perform, how much is sales per month and year, Grouped in year of birth in 5 years, like 1980-1984, 1985-1989. I'd like agegroup to be dynamically created as new column in powerquery for example.
Not exactly clear what you want.
I assumed you always wanted your groupings to start on a multiple of five.
create a list of groupings based on the earliest date of birth rounded down to the nearest multiple of five.
Add a column which has the start year of the grouping
Add another column which takes that year and creates the text that you want for your grouping
Original data
M Code
let
Source = Excel.CurrentWorkbook(){[Name="Table24"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"idcustomer", Int64.Type}, {"year of birth", Int64.Type},
{"amount", Int64.Type}, {"salesdate", type date}}),
//add grouping column depending on min/max year of birth
//round firstYear down to a multiple of 5
firstYear =Number.IntegerDivide(List.Min(#"Changed Type"[year of birth]),5)*5,
lastYear = List.Max(#"Changed Type"[year of birth]),
//create list of groupings
groupings = List.Numbers(firstYear, Number.IntegerDivide(lastYear-firstYear,5)+1,5),
//group for first year selected from the list
#"First Year" = Table.AddColumn(#"Changed Type","firstYear",
each List.Last(List.Select(groupings, (li)=> li <= [year of birth])), Int64.Type),
//grouping column added as text
#"Add Grouping Column" = Table.AddColumn(#"First Year","Grouper",
each Text.From([firstYear]) & "-" & Text.From([firstYear]+4),type text),
//remove first year column
#"Removed Columns" = Table.RemoveColumns(#"Add Grouping Column",{"firstYear"})
in
#"Removed Columns"
Results
Your question is poorly described, but sample code below for powerquery sets up the columns for year, month, and bucket. You can then group on bucket column and one of the other columns to do whatever math you want
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"idcustomer", Int64.Type}, {"year of birth", Int64.Type}, {"amount", Int64.Type}, {"salesdate", type date}}),
// add columns for year, month and year/month
// you could probably do some math on the year instead, but too lazy to figure it out
#"Added Custom1" = Table.AddColumn(#"Changed Type", "SalesYear", each Date.Year([salesdate])),
#"Added Custom2" = Table.AddColumn(#"Added Custom1", "SalesMonth", each Date.Month([salesdate])),
#"Added Custom3" = Table.AddColumn(#"Added Custom2", "MonthYear", each #date(Date.Year([salesdate]),Date.Month([salesdate]),1)),
// generate list of buckets from 1940 through 2050, every 5 years
List = Table.FromList(List.Transform(List.Generate(() => 1940, each _ < 2050, each _ + 5), each Text.From(_)), null, {"Bucket"}),
#"Added Custom" = Table.AddColumn(List, "Year", each {Number.From([Bucket]) .. Number.From([Bucket])+4 }),
#"Expanded Year" = Table.ExpandListColumn(#"Added Custom", "Year"),
// add bucket column
#"Merged Queries" = Table.NestedJoin(#"Added Custom3", {"year of birth"}, #"Expanded Year", {"Year"}, "Table2", JoinKind.LeftOuter),
#"Expanded Table2" = Table.ExpandTableColumn(#"Merged Queries", "Table2", {"Bucket"}, {"Bucket"})
in #"Expanded Table2"
I'm using PowerBI and looking to summarize (average) data over a period of time, however I realized that my source data doesn't reflect "empty" (zero totals) date values. This are valid and required for accurately aggregating totals over a period of time.
I've created a new date table using the following expression, to create all the dates within the preliminary tables range:
Date_Table = CALENDAR(MIN('SalesTable'[Daily Sales Date]),MAX('SalesTable'[Daily Sales Date]))
However, when trying to create a relationship with the created table and the original SalesTable to fill in the "missing dates" I haven't been successful. If anyone has encountered this a similar issue and has any advice or could point me towards resources to resolve this, I would be greatly appreciative.
I've included an example of my current and expected results below. Thanks!
current:
Item Group
Daily Sales Date
Total
Fruit
January 1
5
Vegetable
January 5
10
expected:
Item Group
Daily Sales Date
Total
Fruit
January 1
5
Fruit
January 2
0
Fruit
January 3
0
Fruit
January 4
0
Fruit
January 5
0
Vegetable
January 1
0
Vegetable
January 2
0
Vegetable
January 3
0
Vegetable
January 4
0
Vegetable
January 5
10
To do this in Power Query as you request, you can create the Date Table in Power Query, then Join it with each group in the Item Group column:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WcisqzSxR0lHySswrTSyqVDAEsk2VYnWilcJS01NLEpNyUpFkTYFsQwOl2FgA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Item Group" = _t, #"Daily Sales Date" = _t, Total = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"Item Group", type text},
{"Daily Sales Date", type date},
{"Total", Int64.Type}}),
//create a table with a list of all dates for the date range in the table
allDates = Table.FromColumns({
List.Dates(List.Min(#"Changed Type"[Daily Sales Date]),
Duration.Days(List.Max(#"Changed Type"[Daily Sales Date]) - List.Min(#"Changed Type"[Daily Sales Date]))+1,
#duration(1,0,0,0))},type table[Dates=date]),
//group by the item group column
//Then join each subtable with the allDates table
group = Table.Group(#"Changed Type",{"Item Group"},{
{"Daily Sales Date", each Table.Join(_,"Daily Sales Date",allDates,"Dates",JoinKind.RightOuter)}
}),
//Expand the grouped table
#"Expanded Daily Sales Date" = Table.ExpandTableColumn(group, "Daily Sales Date", {"Total", "Dates"}, {"Total", "Dates"}),
//replace the nulls with zero's
#"Replaced Value" = Table.ReplaceValue(#"Expanded Daily Sales Date",null,0,Replacer.ReplaceValue,{"Total"}),
//set proper column order and types
#"Reordered Columns" = Table.ReorderColumns(#"Replaced Value",{"Item Group", "Dates", "Total"}),
#"Changed Type1" = Table.TransformColumnTypes(#"Reordered Columns",{{"Dates", type date}, {"Total", Int64.Type}})
in
#"Changed Type1"
If you wanted to average over the existing date range, you can try this:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WcisqzSxR0lHySswrTSyqVDAEsk2VYnWilcJS01NLEpNyUpFkTYFsQwOl2FgA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Item Group" = _t, #"Daily Sales Date" = _t, Total = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{
{"Item Group", type text},
{"Daily Sales Date", type date},
{"Total", Int64.Type}}),
//count the number of dates
numDates = Duration.Days(List.Max(#"Changed Type"[Daily Sales Date]) - List.Min(#"Changed Type"[Daily Sales Date]))+1,
//group by Item Group, then average using Sum/Number of dates for each subgroup
#"Grouped Rows" = Table.Group(#"Changed Type", {"Item Group"}, {
{"Average", each List.Sum([Total])/numDates}})
in
#"Grouped Rows"
And there are numerous other ways of accomplishing what you probably require.
I have DirectQuery connection to SQL server. In this query I have Date table with values like 20200414 and 20200415 etc.
I want to use a slicer visualization to be able to pick between the last 7 days as a slider. When I make a slicer visualization and add my existing Date table the slicer only shows values as tickbox but I want a slider. I created a new date hierarchy and got the slider I needed but now I need to link it to my existing date table.
I do not have similar columns in my date hierarchy and date table.
Existing:
Date Hierarchy:
How can I create a similar working Date Hierarchy that has a column like in my existing table? So I could just manage relationships for them to work.
Code I use in my hierarchy:
let
StartDate = #date(StartYear,1,1),
EndDate = #date(EndYear,12,31),
NumberOfDays = Duration.Days( EndDate - StartDate ),
Dates = List.Dates(StartDate, NumberOfDays+1, #duration(1,0,0,0)),
#"Converted to Table" = Table.FromList(Dates, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "FullDateAlternateKey"}}),
#"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns",{{"FullDateAlternateKey", type date}}),
#"Inserted Year" = Table.AddColumn(#"Changed Type", "Year", each Date.Year([FullDateAlternateKey]), type number),
#"Inserted Month" = Table.AddColumn(#"Inserted Year", "Month", each Date.Month([FullDateAlternateKey]), type number),
#"Inserted Month Name" = Table.AddColumn(#"Inserted Month", "Month Name", each Date.MonthName([FullDateAlternateKey]), type text),
#"Inserted Quarter" = Table.AddColumn(#"Inserted Month Name", "Quarter", each Date.QuarterOfYear([FullDateAlternateKey]), type number),
#"Inserted Week of Year" = Table.AddColumn(#"Inserted Quarter", "Week of Year", each Date.WeekOfYear([FullDateAlternateKey]), type number),
#"Inserted Week of Month" = Table.AddColumn(#"Inserted Week of Year", "Week of Month", each Date.WeekOfMonth([FullDateAlternateKey]), type number),
#"Inserted Day" = Table.AddColumn(#"Inserted Week of Month", "Day", each Date.Day([FullDateAlternateKey]), type number),
#"Inserted Day of Week" = Table.AddColumn(#"Inserted Day", "Day of Week", each Date.DayOfWeek([FullDateAlternateKey]), type number),
#"Inserted Day of Year" = Table.AddColumn(#"Inserted Day of Week", "Day of Year", each Date.DayOfYear([FullDateAlternateKey]), type number),
#"Inserted Day Name" = Table.AddColumn(#"Inserted Day of Year", "Day Name", each Date.DayOfWeekName([FullDateAlternateKey]), type text)
in
#"Inserted Day Name"
What you can do is duplicate the column SalesDate in the Query Editor and then change the data type of your new column to Date. The result should be like this
Then you can easily connect both of your tables.
Distribute a value evenly across a start date and end date into daily buckets.
Working with a Date Table
TBTR value split evenly between Todays Date - End Date.
There are nine days (3/29-4/7), each day would have a value of 2.91 bucketed by day so that 2.91 per day for that period could ultimately be graphed.
Here you go, it will create extra rows what you can use to your liking:
let
Source = Excel.Workbook(File.Contents("C:\...\Test.xlsx"), null, true),
Sheet1_Sheet = Source{[Item="Sheet1",Kind="Sheet"]}[Data],
#"Promoted Headers" = Table.PromoteHeaders(Sheet1_Sheet, [PromoteAllScalars=true]),
#"Added Custom1" = Table.AddColumn(#"Promoted Headers", "TBTRAverage", each [TBTR] / Duration.Days([End date]-[Todays date])),
#"Added Custom" = Table.AddColumn(#"Added Custom1", "Date", each let EndThisRow = [End date] in List.Generate(()=>[Todays date], each _ <= EndThisRow , each Date.AddDays( _ , 1))),
#"Expanded Date" = Table.ExpandListColumn(#"Added Custom", "Date"),
#"Changed Type" = Table.TransformColumnTypes(#"Expanded Date",{{"Date", type date}})
in
#"Changed Type"
Result: