How to get MDX openingperiod() to work as calculated measure in ssas cube - visual-studio

I want to use the MDX functions openingperiod() and closingperiod() in our cube, but cannot get it to work properly.
Is this actually possible, or are these functions only applicable in a MDX-query?
The main two articles I used to learn about openingperiod() are:
https://www.sqlservercentral.com/steps/stairway-to-mdx-level-12-mdx-timedate-series-functions-openingperiod-and-closingperiod-functions
https://learn.microsoft.com/en-us/sql/mdx/openingperiod-mdx?view=sql-server-2017
In the above documentation the two functions openingperiod() and closingperiod() are only used in a query, but I want to integrate them in the cube.
The code I used as a regular query is:
sum(
openingperiod
(
[Date Booking].[Year Month],
[Date Booking].[Year Month].currentmember
),
[Measures].[Goods Amount])
The result should be the amount of goods at the start of the month, but the result is NULL.
I used sum to get a valid syntax that points to the right member.

I will try to give you the idea from Adventure Works sample database.
This should be the syntax to create your calculated member in the cube ([Adventure Works] is the cube name in this example), so you can call it later:
create member [Adventure Works].Measures.MyMeasure4
as
(OpeningPeriod([Date].[Calendar].[Date],[Date].[Calendar].Currentmember.Parent), [Measures].[Internet Sales Amount])
And then you should call it like this to see the result:
select {Measures.MyMeasure4, [Measures].[Internet Sales Amount]} on 0,
[Date].[Calendar].members on 1
from [Adventure Works]
So for January, MyMeasure4 will have the value of January the 1st member (value for opening period), for February it will have the value from Feb the 1st, if that was your intention.

Related

Microsoft Power BI, DAX - tricky ALLSELECTED with 2 values in slicer, but show only TOP 1 row in visual

This question is an extension of an already answered question, which I posted this week.
I have the below situation in Microsoft Power BI.
I have 2 simple tables:
1) CountryTable
2) YearTable
There is a 1-M relationship between YearTable and CountryTable.
The latter (YearTable) is used to feed values into a slicer.
(In my client database, Year has some alphabetical prefixes, such as Q1-2022, so I prefer to use YearOrder column to sort the Year column at the backend, while the slicer will display the Year column.)
The former (CountryTable) is the main table, with just a few sample rows.
These two tables are related via the Year column.
The Year slicer always has EXACTLY 2 values chosen in my Power BI report.
I need the Maximum of these two values of the year slicer as a measure, for each row of my visual.
At the same time, these two year values of the slicer must remove the unwanted rows in my report visual, based on the slicer selection of year values.
For example, when the slicer has 2019 and 2020 chosen, I need the value as in the DesiredOutput1 page.
Similarly, you can see DesiredOutput2 (Slicer values are 2020 and 2022); DesiredOutput3 (Slicer values are 2019 and 2022) pages.
I have indeed successfully obtained DesiredOutput1, DesiredOutput2, DesiredOutput3. Thanks to all the folks who helped me attain this.
Now, my main requirement in this posting, is this:
After obtaining the DesiredOutputs above, I need the following output:
Show only the TOP 1 row (ASC order of Year column, which is the minimum value of the slicer).
Essentially:
Year column of the visual: Minimum value of the slicer
MaxYear_Measure_SlicerSelection: Maximum value of the slicer (maximum of the two values chosen in the slicer)
You can see below:
Note: MaxYear_Measure_SlicerSelection measure can refer to any one of the two measures [MaxYear] or [MaxYearMeasure_Community] (see the .pbix file for the formulas of the measures).
Any idea ?
I prefer the Year column of the visual not to be converted to a new measure. Would RANKX help in this case ? Any thoughts?

MDX openingperiod, closingperiod and sum(measure) return the same value

In our cube we want to develop an overview of the amount of goods and their value at the beginning and closing of a month. So I want to use the MDX expressions openingperiod() and closingperiod(), they should provide these metrics.
In Visual Studio we have the following code (only for openingperiod() since closingperiod() has the same syntax)
(OPENINGPERIOD
(
[Date Booking].[Month].[Month],
[Date Booking].[Month].currentmember
),
[Measures].[AT Amount])
The results for openingperiod() and closingpeiod() are the same as well as for the measure [AT Amount] = sum(Amount)
I expected three different outcomes, as documentations and examples show. However all three outcomes are the same.
Consulted pages:
https://learn.microsoft.com/en-us/sql/mdx/openingperiod-mdx?view=sql-server-2017
https://www.sqlservercentral.com/steps/stairway-to-mdx-level-12-mdx-timedate-series-functions-openingperiod-and-closingperiod-functions
Comparing your code against the example, I suspect you are trying to use this technique against hierarchy with a single level.
The example was for a multi-level hierarchy Year / Semester / Quarter / Month / Date. In that scenario, when using the Month level to slicer your measure, the CURRENTMEMBER property returns each Month member, which is applied to return first the child member at the Date level (as specified in the 1st parameter of OPENINGPERIOD).
With your code, the CURRENTMEMBER property returns each Month member, which is applied at the Month level, so it will return the same Month member for OPENINGPERIOD or CLOSINGPERIOD (or effectively use the same Month member for SUM).
I would construct a Calendar hierarchy with Date level below a Month level (other levels are optional), then I would edit your code to:
(OPENINGPERIOD
(
[Date Booking].[Calendar].[Date],
[Date Booking].[Calendar].currentmember
),
[Measures].[AT Amount])

Time Series Projection in Google BigQuery

I was looking for a good way to do time series projection in BigQuery, and found this one, which nicely works to calculate correlations and slope: View Post. But it doesn't help to extend the timeline to your choice.
But can anyone please suggest a complete solution, where I can extend the timeline (x) according to my need and get projections of (Y) using a single query?
Any help will be highly appreciated.
The basic idea is to left join the model specs to a generated dates table and use it:
WITH stats AS (
SELECT * FROM UNNEST([
STRUCT( 'a' AS model, 0.3 AS slope, 11 AS intercept ),
STRUCT( 'b', 0.2, 7)
])
)
SELECT
date,
model,
slope,
intercept,
UNIX_DATE(date) AS X,
slope * UNIX_DATE(date) + intercept AS Y
FROM
UNNEST(GENERATE_DATE_ARRAY(DATE('2018-05-01'),DATE('2018-07-01'))) AS date
LEFT JOIN stats ON TRUE
ORDER BY date ASC
I did not repeat the statistics part since it is already answered, but I created a dummy table with two models which replaces it, The model can also be a bucket of course, then you'd have to left join on that as a key.
I'm also assuming you created the model with dates using unix date (days since 1970-01-01), if not you need to modify accordingly.

Cognos 11 Crosstab - need a value that doesn't have a reference to the column values

Crosstab report works 99%.
About 20 rows, all but one are ok.
5 columns - Company Division.
The rows are things like cost, revenue, revenue 2, etc.
All the rows that work have three attributes I'm using to select them:
Fiscal Year
Period
Solution.
The problem is there is table that lists an YTD rate for each period. This table is not Division Specific; it's company wide.
All the tables are linked to the accounting period table that has fiscal year and period. So the overall query limits data to fiscal year (?pFiscalYear?) and period <= ?pPeriod?, based on prompt page results.
The source table has this:
FY_CD PD_NO ACT_CURR_RT ACT_YTD_RT
2018 1 0.36121715 0.36121715
2018 2 0.32471476 0.34255512
2018 3 0.25240906 0.31210183
2018 4 0.33154745 0.31925874
Note the YTD rate is not an average of any of the other numbers.
When I select the ACT_YTD_RT, as a row, I want the ACT_YTD_RT that matches the selected period.
What I get is the average if I set the aggregation to average or the lowest if I set it to other aggregations. So sometimes, it looks right (if I run for period 1,2,3, as the rate kept falling), and sometimes it's wrong (period 4
returns .3121 instead of .3192).
I've tried a number of different methods and can generate garbage data (totals, min, max, average) and crossjoins but can't figure out how to get the value I'm looking for.
I want YTD_RT where fiscal year =?pFiscal? and period = ?pPeriod?.
I tried a straight if then clause:
if (sourcetable.fiscalYear = ?pFiscalYear?) and (sourcetable.Period = ?pPeriod?) then (ACT_YTD_RT)
but I get an error like this:
'ACT_YTD_RT' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. (SQLSTATE=42000, SQLERRORCODE=8120)
If I create another query that generates the right response and try to include it, I get a crossjoin error that the query I'm referencing is trying to crossjoin several other items in the crosstab query.
A union doesn't work (different number of columns).
Not sure how a join would work since the division doesn't exist in the rate table.
I maybe could create a view in the database that did a crossjoin of the division table and the rate table, add that to the framework and then I wouldn't have a crossjoin since the solution would be in the rate "table" (really view), but that seems wrong somehow.
If I could just write a freaking parameterized query direct to the database I'd be done. But in Cognos 11 crosstabs I can't find a place for a SQL query object. And that shouldn't be necessary.
I've spent hours and hours chasing this in circles.
Anybody have any ideas?
Thanks
Paul
So the earlier problem was that this:
if (sourcetable.fiscalYear = ?pFiscalYear?) and (sourcetable.Period = ?pPeriod?) then (ACT_YTD_RT)
Generated an error like this:
'ACT_YTD_RT' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. (SQLSTATE=42000, SQLERRORCODE=8120)
To fix the above, I had to add a cross join of the division table and the rate table as a view in the database. Then add that to the framework. Then build the data item this way:
total (
if (sourcetable.fiscalYear = ?pFiscalYear?) and (sourcetable.Period = ?pPeriod?) then (ACT_YTD_RT)
)
And now the "total" provides the missing group by. And the crossjoin in the database provides the division information so the crosstab is happy.
I still think there should have been an easier way to do this, but I have a functioning hammer at the moment.

MDX Query to find the last ever non empty value in icCube

Following the post from Chris Web I am looking for a fast way to find the last buy from a customer.
I use an MDX statement like the following:
WITH FUNCTION previous_buys() AS tail( nonempty({NULL:[Time].[Time].currentmember.prevmember} ,[measures].[sales amt]),1)
MEMBER [last buy] as previous_buys().(0).key
select [measures].[last buy] on 0
, [Customers].[Customers].[name].members on 1
from [Store Sales]
where [Time].[Time].[day].&[2015-12-20T00:00:00.000]
This gives as expected, but it is taking a very long time. Is there an easy way to speed this query up somehow. As icCube is somewhat different then the Microsoft MDX I can not just copy Chris Web's solution.
Any idea's?
The main problem we're going to have with this solution is the scalability as we're evaluating {NULL:[Time].[Time].currentmember.prevmember} count members.
I thought that using a Reverse with a Head function would not evaluate the whole set, but the current implementation of the Empty function 'materializes' the set. This means we're evaluating all members. Not yet a valid solution.
Another solution and more elegant is using a recursive function. This will should reduce drastically the number of members evaluated.
WITH
FUNCTION previous_buys(t_) AS IIF( (t_,[Measures].[Amount]) = NULL, previous_buys(t_.prevMember), t_ )
MEMBER [last buy] as previous_buys( [Time].[Calendar].current).name
SELECT
[measures].[last buy] on 0,
[Customers].[Geography].[Region] on 1
FROM [Sales]
WHERE [Time].[Calendar].[Year].[2006].[Q1 2006].[Jan 2006].[8 Jan 2006]
If you've a lot of empty dates you could complicate a bit the algorithm going down to a month level for checking emptiness. This will evaluate a whole month in one iteration instead of the 30/31 we'll have in the day version.
The last and fastest by an order of magnitude is relying of the aggregation engine of icCube. What we want here is a measure that returns the last existing day.
The idea would be to add a measure with a date as input value and max as aggregation method. Then we would use eval - important as we're caching the subcube - on the set with this new measure.
This is relatively quick using SSAS against AdvWrks. I amalgamated you two custom structures (& needed to change from FUNCTION as I don't think this is part of MS's implementation of mdx):
WITH
MEMBER [Measures].[previous_buys] AS
Tail
(
NonEmpty
(
{NULL : [Date].[Calendar].CurrentMember.PrevMember}
,[Measures].[Internet Sales Amount]
)
).Item(0).Item(0).Member_Key
SELECT
NON EMPTY
[Measures].[previous_buys] ON 0
,NON EMPTY
[Product].[Product Categories].[Product] ON 1
FROM [Adventure Works]
WHERE
[Date].[Calendar].[Date].&[20071015];
It results in the following:

Resources