Dynamic minimum and maximum dates using M/Power Query - powerquery

I have a calendar table that is created, on-the-fly, using M.
It starts like this:
let
StartDate = #date(2016, 1, 1),
EndDate = #date(2018, 12, 31),
//Used for 'Offset' Column calculations, you may Hard code CurrentDate for testing e.g. #date(2017,9,1)
CurrentDate = DateTime.Date(DateTime.FixedLocalNow()),
// Specify the last month in your Fiscal Year, e.g. if June is the last month of your Fiscal Year, specify 6
FiscalYearEndMonth = 6,
#"==SET PARAMETERS ABOVE==" = 1,
#"==Build Date Column==" = #"==SET PARAMETERS ABOVE==",
ListDates = List.Dates(StartDate, Number.From(EndDate - StartDate)+1, #duration(1,0,0,0)),
...
...
Is it possible to make the first two lines dynamic so that they pick up minimum and maximum dates from database tables? So these two lines:
let
StartDate = #date(2016, 1, 1),
EndDate = #date(2018, 12, 31),
I have another table being loaded into the model using the following - can I somehow use the Date column from this loads to dynamically set StartDate and EndDate ?
let
Source = Sql.Database("ourServer", "ourDB"),
tb_ModelFact = Source{[Schema="dbo",Item="tb_ModelFact"]}[Data],
#"Changed Type" = Table.TransformColumnTypes(tb_ModelFact,{{"Date", type datetime}}),
#"Filtered Rows" = Table.SelectRows(#"Changed Type", each true),
#"Changed Type1" = Table.TransformColumnTypes(#"Filtered Rows",{{"Amount", type number}})
in
#"Changed Type1"
Edit
So I tried this
StartDate = List.Min(Fact[Date]),
EndDate = List.Max(Fact[Date]),
....and got this mysterious error?
Expression.Error: We cannot convert the value #datetime(2016, 1, 6, 0, 0, 0) to type Date.
Details:
Value=06/01/2016 00:00:00
Type=Type
Is this error in subsequent M code after the declaration?

Yes. You should be able to write something along these lines:
let
StartDate = List.Min(tb_ModelFact[Date]),
EndDate = List.Max(tb_ModelFact[Date]),
where tb_ModelFact[Date] is the column that has the dates you are trying to take the max and min from.
You will need to change tb_ModelFact to whatever the name of that second query is though.

Related

Value returned based on specific time requirements

I'm trying to figure out an issues in my report. 
I have a list of items with cost that is being changed at random intervals (my current dataset includes data from 1/1/22 - 31/1/23). I have managed to write some measured to get first and last cost based on filter context: 
_lastOldIDC =
VAR tbl = VALUES('IDCs')
VAR max_date = MAXX('IDCs', [Maximum of Date])
VAR result =  MINX(FILTER(tbl, [Maximum of Date] = max_date), [Old Value])
RETURN
result
_firstOldIDC =
VAR tbl = VALUES('IDCs')
VAR min_date = MINX('IDCs', [Maximum of Date])
VAR result =  MINX(FILTER(tbl, [Maximum of Date] = min_date), [Old Value])
RETURN
result
my table
These two work great but now I need a similar measure that will only return a value (cost change) that represents the last value in the column before 10/11/2022. In the example based on the screenshot the value returned would be £2.43 as a last value in the column before the threshold (10/11/22). My measures can filter out other values and dates if I use a slicer but that only captures defined space of time and not the last cost change done prior to 10/11/2022. 
Any help here would be massively appreciated. 

PowerQuery - use position of column instead of column name in calculation

New to PowerQuery and M-Code.
I have added a column with a calculation to get the max. Instead of using the hardcoded column name, I would like to use the position number of the column.
The current code is:
= Table.AddColumn(Source, "Maximum", each List.Max({[#"1-6-2021"], [#"1-5-2021"], [#"1-4-2021"]}), type number)
Instead of [#"1-6-2021"], I would like it to be column 3; for [#"1-5-2021"] column 4 etc.
How do I replace these columnnames with positions?
Many thanks for the help!
You can adjust the {x} part for the column # you want
0 is the first column, so this is max of columns 2/3/4
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
x= Table.AddColumn(Source, "Maximum", each List.Max({
Record.Field(_,Table.ColumnNames(Source){1}),
Record.Field(_,Table.ColumnNames(Source){2}),
Record.Field(_,Table.ColumnNames(Source){3})
}), type number)
in x
If you need to do a Max on a bunch of columns, below would, for example, do it for all columns except the first two, which are removed by the 2nd line
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
colToSum = List.RemoveFirstN(Table.ColumnNames(Source),2),
AddIndex = Table.AddIndexColumn(Source,"Index",0,1),
GetMax = Table.AddColumn(AddIndex, "Custom", each List.Max( Record.ToList( Table.SelectColumns(AddIndex,colToSum){[Index]}) ))
in GetMax

PowerQuery - Dynamic Date Parameter

I have the following PowerQuery in Excel
let
Source = Excel.CurrentWorkbook(){[Name="Query1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Month Year", type date}}),
#"Custom Step" = Table.SelectRows(#"Changed Type", each [Month Year] = #date(2017, 12, 1))
in
#"Custom Step"
I would like to set this up so that #date(2017, 12, 1)) is a parameter. In other words, I want to have a filter/dropdown on a worksheet and whatever the user selects (December 2017, November 2016, etc.) I want the "Custom Step" to filter the table based on the selection.
Is there some sort of syntax that will allow me to use a parameter? (kinda like #variable in SQL)
There are many different ways to get a parameter for a query. You can use a named range and access it directly or with a function, or you can even build a table with several parameters and access them with a function. Ken Puls has a good starting point for parameter tables here
With just one parameter, you can simply use a named range. In the following screenshot, cell F4 has the range name SelectedDate. It is easy to get this parameter with the line
myDate = Excel.CurrentWorkbook(){[Name="SelectedDate"]}[Content]{0}[Column1]
but the result will be text and won't filter the table correctly. You need to convert it into a date, for example by wrapping it into a Date.From function
myDate = Date.From(Excel.CurrentWorkbook(){[Name="SelectedDate"]}[Content]{0}[Column1]),
Now the variable myDate can be used to filter the table. Here is the complete M code:
let
myDate = Date.From(Excel.CurrentWorkbook(){[Name="SelectedDate"]}[Content]{0}[Column1]),
Source = Excel.CurrentWorkbook(){[Name="Query1"]}[Content],
ChangedType = Table.TransformColumnTypes(Source,{{"Month Year", type date}}),
Filtered = Table.SelectRows(ChangedType, each [Month Year] = myDate )
in
Filtered

DAX EARLIER() function in Power Query

Is there an an equivalent to EARLIER in M/Power Query?
Say, I have a table with lots of different dates in column DATE and a smaller number of letters in column LETTER. I now want the maximum date for each letter.
In DAX, I would use something like CALCULATE(MAX([Date]),FILTER(ALL(Table),[Letter]=EARLIER([Letter])).
How would I achieve the same in M?
Thanks
2 Solutions in the code below. Notice that each uses "PreviousStep" as basis, so these are separate solutions.
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
PreviousStep = Table.TransformColumnTypes(Source,{{"Date", type date}, {"Letter", type text}}),
// 1. Add a column to the original table with the MaxDate for each letter
// "earlier" is just the name of a function parameter; it could as well have been "x" or "MarcelBeug"
AddedMaxDate = Table.AddColumn(PreviousStep, "MaxDate", (earlier) => List.Max(Table.SelectRows(PreviousStep, each [Letter] = earlier[Letter])[Date])),
// 2. Group by letter and get the MaxDate for each letter
GroupedOnLetter = Table.Group(PreviousStep, {"Letter"}, {{"MaxDate", each List.Max([Date]), type date}})
in
GroupedOnLetter
In short, there is no exact match for this function. Still, you can use other ways that can produce same results.
To reproduce example offered by Microsoft in help for EARLIER function, you can use following code (table1 equals table given in the example before ranking):
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("TVNNaxtBDP0rxuSoivn+uMYlLSUFE4f2YHIYd4d48Xq3rO1C/n01o1mc4+i9kZ6epP1+LcMa1o/94cvuOM3XCz0epHUgnccQ1m+wXytXGae8ekl/TpWhlACvBHrBDL8wdtc0dpWiLTgV0EVm1CrT9Trky4ooq016z5VnI2ij0OjKs402nVePM1XLrMgEcEaj8ZVU9czpxAmcAik1SlcxGSm2SX/5m4eoDVpToSJyc0z9WLEAwXgUrcX6a8hpzDNb4CAEhU5VuIjfzGk8XZoeGSVYpVBwd+X31zynfhjyjRM4A9FZ1NyWFhR7ymPX0hsJ0RuUbJ+s6DSzt96QtR4d96MK9m2Y/uVmfABtNVrWbSj2newc8iEtwjUoS401O2Rh5NQtyq0HZyNGFq4ZHs6Lz1aCjAopXmFV4I9uTtd+GlfbZfyR3IkafTOvJPlBneUPbj1GMCouMFkA6+f+/VhLcKjofp5aNmlBkKQ23JLs53QbrzSoVdkp3iYDWlgIzqBi6VJ9Jj7N6cxMA1ZSE16ga/XLTm3TOPZsPv8uora5SwNLMIIkK1Q8EF02bHs78xZJBS5alK1bCr1Mqbtro7+WfHPRoeZNk2Yh3XVpcNqBjgE9myuLrl3qaHg8GUUr5RYbVKlzP0kdLHhBJ9kOrsjfLQaWndCEWcZK8dfF7wcZIrkRUXNe7Ss6tzN8vR2WxTIQtMLQJl9Y023ux/d7o1JTHVOH0MyQ7hPv3isdh7F01gYFH5Aqvf7KF5akyLEYBYrmVpH0+5jz0C4nADEq+vYf", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [ProductSubcategoryKey = _t, EnglishProductSubcategoryName = _t, TotalSubcategorySales = _t]),
table1 = Table.TransformColumnTypes(Source,{{"ProductSubcategoryKey", Int64.Type}, {"EnglishProductSubcategoryName", type text}, {"TotalSubcategorySales", Currency.Type}}, "en-US"),
AddCount = Table.AddColumn(
table1,
"SubcategoryRanking", //(a) is a parameter for function, which equals current record, and function should return value for new cell of "SubcategoryRanking"
(a)=> Table.RowCount(
Table.SelectRows(
table1, //(b) equals whole table1. This function returns table filtered by given criteria
(b) => b[TotalSubcategorySales] < a[TotalSubcategorySales])
) + 1,
Int64.Type)
in
AddCount
I think you can use the GroupBy function to group the data by Letter and find the Max of the date column. So your code should look like.
= Table.Group(#"Previous step", {"Letter"}, {{"Max Date", each List.Max([Date]), type date}})

How to get month name from month number in Power BI?

I have Year number and Month Number in my data.
How using DAX can I get the month name out of month number?
In SSRS its very easy. But how to achieve that using DAX?
You can use:
MonthName = FORMAT(DATE(1, [Num], 1), "MMM")
Result:
Nothing fancy, simply a reconstruction of a fake date from the month number provided, and reformat it with the FORMAT function.
Of course as an alternative you can go the old-fashioned way and write a SWITCH statement and hard-coded for the 12 months. It's up to you.
You can try this too:
Month name = FORMAT('Table'[date_column], "MMM")
If you use single quotes in 'MMM', it doesn't work. Ensure to use ""
By Use of Switch DAX function
MonthName = switch(True(),
MonthID = 1, "jan",MonthID = 2, "Feb",MonthID = 3, "March",MonthID = 4, "April",MonthID = 5, "May",MonthID = 6, "June",MonthID = 7, "july",MonthID = 8, "Aug",MonthID = 9, "Sept",MonthID = 10, "Oct",MonthID = 11, "Nov",MonthID = 12, "Dec"
)

Resources