Subselecting with MDX - filter

Greetings stack overflow community.
I've recently started building an OLAP cube in SSAS2008 and have gotten stuck. I would be grateful if someone could at least point me towards the right direction.
Situation: Two fact tables, same cube. FactCalls holds information about calls made by subscribers, FactTopups holds topup data. Both tables have numerous common dimensions one of them being the Subscriber dimension.
FactCalls FactTopups
SubscriberKey SubscriberKey
CallDuration DateKey
CallCost Topup Value
...
What I am trying to achieve is to be able to build FactCalls reports based on distinct subscribers that have topped up their accounts within the last 7 days.
What I am basically looking for an MDX equivalent to SQL's:
select *
from FactCalls
where SubscriberKey in
( select distinct SubscriberKey from FactTopups where ... );
I've tried creating a degenerate dimension for both tables containing SubscriberKey and doing:
Exist(
[Calls Degenerate].[Subscriber Key].Children,
[Topups Degenerate].[Subscriber Key].Children
)
Without success.
Kind regards,
Vince

You would probably find something like the following would perform better. The filter approach will be forced to iterate through each subscriber, while the NonEmpty() function can take advantage of optimizations in the storage engine.
select non empty{
[Measures].[Count],
[Measures].[Cost],
[Measures].[Topup Value]
} on columns,
{
NonEmtpy( [Subscriber].[Subscriber Key].Children,
( [Measures].[Topups Count],
[Topup Date].[Calendar].[Month Name].&[2010]&[3] ) )
} on rows
from [Calls] ;

You know how sometimes it's the simplest and most obvious solutions that somehow elude you? Well, this is apparently one of them. They say "MDX is not SQL" and I now know what they mean. I've been working at this from an entirely SQL point of view, completely overlooking the obvious use of the filter command.
with set [OnlyThoseWithTopupsInMarch2010] as
filter(
[Subscriber].[Subscriber Key].Children,
( [Measures].[Topups Count],
[Topup Date].[Calendar].[Month Name].&[2010]&[3] ) > 0
)
select non empty{
[Measures].[Count],
[Measures].[Cost],
[Measures].[Topup Value]
} on columns,
non empty{ [Test] } on rows
from [Calls] ;
Embarrassingly simple.

Related

Filter settings in Oracle Views

I have 2 views like this (simplified):
CREATE VIEW BASE_VIEW AS
(
-- Simplified version, view actually does a lot more.
SELECT * FROM MYTABLE;
);
CREATE VIEW OUTER_VIEW AS
(
-- The where clause here makes this view return half the rows as the above BASE_VIEW
SELECT * FROM BASE_VIEW where SomeField = 'something'
);
My question is, shouldn't OUTER_VIEW execute in roughly half the time as the BASE_VIEW? I don't see this behavior. It almost takes the full time as it takes to execute BASE_VIEW.
Since Oracle compiles the referenced views into your outer view, I thought it would be intelligent enough to optimize the query based on the outer view's where clase. Should it not?
EDIT: In fact the "base view" query with the where clause from the "outer view" is taking half the time.
Imagine you have an entire room full of different kinds of fruit scattered all over the place. The view BASE_VIEW is like saying, "Retrieve all fruit in this room."
The OUTER_VIEW is like saying, "Retrieve all oranges from this room." If the fruit is not ordered in some way, you will spend roughly the same amount of time as the BASE_VIEW to search for all the oranges.
Now imagine you have all the fruit separated in baskets. Grabbing all the oranges becomes easy because you know exactly where they are.
Adding an index on SomeField is what orders the data so that it doesn't have to search through the entire room of fruit. There are some restrictions on when an index could help or not. Based on the amount of rows in your table, the oracle optimizer might decide that it is faster to just grab all the rows anyway. I suggest you read through this guide to determine the proper way to index tables: Use The Index, Luke. It helped me a ton when starting out indexing.
If SomeField does not directly come from MYTABLE and is just a created field in BASE_VIEW, then it might help to index the field that creates SomeField. It is hard for us to know without seeing the data.

Add multiple calculating filters in MDX

I am really new to MDX but I have spent the past two days looking for an answer but failed. So I greatly appreciate your help and patience.
I am trying to query a Cube with filters on multiple dimensions, and I realize that there are many similar questions already there, like this or this.
The thing is, instead of specifying a particular content I am looking for, I am trying to set up filters that picks up all records that begins with a specific string. This requires left function in the filters (i.e. calculating filters?) but I cannot blend them nicely into the code.
My failed code is like this (the two filters should be in ANDrelation)
Select Non Empty ([Measures].[Sales]) ON 0
FROM [Cube_Name]
WHERE
(
FILTER
(
[Customer].[CustomerID].Members, Left([Customer].[CustomerID].CurrentMember.Name,4)="ABCD"),
[Product].[ProductID].Members, Left([Product].[ProductID].CurrentMember.Name,3)="EFG")
)
)
(My trial is based on the last answer here.)
I also read that there are some workarounds like CROSSJOIN WITH AGGREGATE or Sub-SELECT, but I just do not have any clue on 1)how to incorporate the conditions inside; 2) performance (I heard that CROSSJOIN can be slow).
I am not sure if I should mention it here, but I am actually implementing the MDX from Excel VBA by using the ADOMB.Cellset object. It only gives me the Grand total of the query I implemented under Cellset.Items(0) (there are no more items).
Thank you!
You need to split two sets into two filters:
Select
Non Empty [Measures].[Sales] on 0
From [Cube_Name]
Where
(
Filter(
[Customer].[CustomerID].[CustomerID].Members,
Left(
[Customer].[CustomerID].CurrentMember.Name,
4
) = "ABCD"
),
Filter(
[Product].[ProductID].[ProductID].Members,
Left(
[Product].[ProductID].CurrentMember.Name,
3
) = "EFG"
)
)

SSRS Matrix - Sorting rows by a specific column

Can somebody explain me how to properly sort "[Arrivals] group" by Count(SearchDate)] for particular "Departure" in this Matrix?
I tried this fx in Row Group Sorting Properities, but it didn't work.
[Count(SearchDate)]
Then I tried specify which column I would like to sort, but same problem.
=Count(IIF(Fields!Departures.Value = "PRG", 1, 0))
After deeper inspection I found that I am able to sort "[Arrivals] group" only by [Count(SearchDate)] but not grouped for particular "Departure".
After a advice in MSDN forum I tried this fx:
=IIF(Fields!Departures.Value = "PRG", Count(Fields!SearchDate.Value), 0)
In first view result looks good but only for the first couple of records.
When I tried pivot table in SQL server everything looks fine:
SELECT * FROM (SELECT Arrivals, Departures, SearchDate FROM Destination WHERE SearchDate > '2016-03-01T00:00:00' AND SearchDate < '2016-03-28T14:03:46') as a
PIVOT (COUNT(SearchDate) for Departures in (PRG, LON)) as PivotTable
Order by PRG Desc
I spent a lot of time and tried a lot of solution but I have realy no idea how to solve it.
Thank you very much for your help, Petr.
I faced the same problem before. Try using this expression:
=COUNT(
IIF(
Fields!Departures.Value="PRG",
COUNT(Fields!SearchDate.Value),
Nothing
)
)
It could be a pain since depending on the dataset number of rows it increases the report processing time causing poor performance, it works though.
Let me know if this helps.

Dynamics AX 2012 Subquery in a View

AX allows you to enter basic SQL into View ranges. For example, in an AOT view's range, for the match value, you could enter (StatRepInterval.Name == 'Weekly'). This works nicely.
However, I need to do a more advanced lookup on a View, using a subquery. Can anyone suggest a way to do this?
This is what I would like to use, but I receive an error: "Query extended range failure: Syntax error near 34."
(StatRepInterval.Name == (SELECT FIRSTONLY StatRepInterval.Name FROM StatRepInterval WHERE StatRepInterval.PrintDirection == 1 ORDER BY StatRepInterval.Name DESC))
I've tried a lot of different variants of the subquery, from straight T-SQL to X++ SQL, but nothing seems to work.
Thanks for the help.
Sub-queries are not supported in query expressions.
This may be solved by using additional datasources with inner or outer joins as you observed.
See the spec and Axaptapedida on query expressions.
I found a way to do this. It isn't pretty, and I'm going to leave the question unanswered for a bit, should someone else have a more graceful solution.
Create a source View that contains all fields I wish to return, plus calculated fields that contain my subquery results.
Create a second View that uses the first as a data source, and applies all the necessary ranges.
Works pretty nicely.
Probably inefficient if there were large tables of data, but this is in a relatively small section of AX.

Tabular DAX Daily Many To Many Association

I am almost at the end of my tether on a problem that i have in a model currently... basically, i have a 'temporal' many to many mapping table which maps commission rates for managers over time... these can change daily, (but do so rarely), so I've tried to avoid just having a huge table with the same values repeated albeit for different specific dates, if i do this anyway i end up with a 200 million record table, crucially though more than one manager can get commission for the sale of a certain product type :s
Note: Some commissions only go to a single manager, and some go to multiple, and this can switch over time..
What I've done instead is hold ValidFrom, and ValidTo dates in the mapping table...
Every solution i come up with is deathly slow, and i just have no idea if there even IS a solution at this point... here is a link to a very small sample:- http://1drv.ms/1gOr7uw
The area that i think is the most troublesome is actually getting the correct "rate" for a given Manager, on a given day... the only way i can seem to be able to do this is nested SUMX, but there must be something slicker that I'm missing?!
One thing i thought about (but failed to actually implement) was just to hold an effective date, and filter using that and leverage LASTNONBLANK() or something?
Perhaps someone with some fresh eyes can help me out? Pulling my hair out here!
Edit: Someone will probably say why don't i do this in the ETL, what i've not shown here is that I have other measures that don't need to be split by the managers, but instead the full amount should be reported for each... but the total not a sum of all the managers (aka, default M2M behaviour)
Perhaps I need two fact tables? Perhaps someone could model my data in Excel to achieve a 'split' of the Facts, as i see it, whichever way the problem is cut some calc is going to need to be done at run-time. I think?!
Ty.
Give this a try, I have not checked performance, but I don't expect them to be super... nevertheless, at least it looks elegant :)
Amount :=
SUMX (
SUMMARIZE (
Mapping,
Mapping[Manager],
Mapping[Rate],
Mapping[ValidFrom],
Mapping[ValidTo],
Products[Products],
"SalesInPeriod", Mapping[Rate]
* CALCULATE (
SUM ( Sales[Amount] ),
VALUES ( 'Date'[Date] ),
DATESBETWEEN (
'Date'[Date],
Mapping[ValidFrom],
Mapping[ValidTo]
)
)
),
[SalesInPeriod]
)
If you want to count, still keeping the temporal M2M working, this should do the trick:
Count :=
CALCULATE (
COUNTROWS ( Sales ),
GENERATE (
SUMMARIZE (
Mapping,
Mapping[ValidFrom],
Mapping[ValidTo],
Products[Products]
),
DATESBETWEEN (
'Date'[Date],
Mapping[ValidFrom],
Mapping[ValidTo]
)
),
VALUES ( 'Date'[Date] )
)
This latter version is easier, because it does not need the Rate and Manager (or, it needs the manager, but it is already in the filter context and no SUMX is required since you are aggregating using canonical M2M)

Resources