Checking existence of dimension in MDX - sql-server

How I can check if one dimension exist on axis in MDX statetment?
I need to check how many time units (days, weeks, months...) exist on axis1 and use it to calculate measure. Here is example, what should happen, I take some dimensions:
days -> [Measures].[A] = [Measures].[B] / number of members in axis 1, from only date dimension (365)
months -> [Measures].[A] = [Measures].[B] / number of members in axis 1, from only date dimension (12)
months, product group -> [Measures].[A] = [Measures].[B] / number of members in axis 1, from only date dimension (12)
So dimension different than date dimension should't affect calcutation. I only need to get count on members from [Date] dimension.

A simple example is counting of days:
With
Member [Measures].[Members on rows] AS
Axis(1).Count
Select
Non Empty [Measures].[Members on rows] on columns,
Non Empty [Date].[Day].[Day].Members on rows
From [Sales]
Where [Date].[Month].[Month].&[201701]
But you'll get only row count, you can't predict what's going on with an axis. Also you may check whether the whole attribute count = the report attribute count:
Count(existing [Date].[Day].[Day].Members) = Count([Date].[Day].[Day].Members)
If it returns true, most likely that means you don't use filter the [Date].[Day] hierarchy within your report.

Related

Sumproduct in Netezza

I want to calculate sumproduct in netezza table, where one column is fixed. In frist column (A) I have some numbers in DISCOUNT are discount factors. As a result I want to get sumproduct bewteen A and DISCOUNT, where DISCOUNT always start from first row.
Number in RESULTS:
14,54535 = 5/(1+2%)+3/(1+3%)+7/(1+4%),
9.737293 = 3/(1+2%)+7/(1+3%)
6.862745 = 7/(1+2%)
Always when copunting the next number in columns RESULT, we ignore the previous values from A, but always use the DISCOUNT from MATURITY=1 forward.
MATURITY
A
R
DISCOUNT
RESULT
1
5
2%
98.0392...%
14,54535...
2
3
3%
97.0874...%
9.737293...
3
7
4%
97.0874...%
6.862745...
Is the any way to do that in Neteza? Without using multiple joins for rates/discounts? Since the dimension of data can vary.

How to get multiple parallel periods set?

I would like to create a MDX query which returns a measure value for 15th day of each month between two dates.
For example, the result for 2010-01-01 and 2016-12-15 should be as below:
2016-12-15: 123
2016-11-15: 789
2016-10-15: 556
(...)
2010-01-15: 456
I know I can calculate the number of months between two dates using DateDiff() function. Also, I can use ParallelPeriod() function to get the value for the previous month.
However I have no idea how I can use these values together and "iterate" from 1 to DateDiff() result to create multiple ParallelPeriod() calls in the "Days" set.
WITH
MEMBER NumberOfMonths AS
DateDiff("m",
[Calendar].[Day].&[20100101].MemberValue,
[Calendar].[Day].&[20160315].MemberValue
)
SET Days AS {
PARALLELPERIOD([Calendar].[Month], 1, [Calendar].[Day].&[20160315]),
PARALLELPERIOD([Calendar].[Month], 2, [Calendar].[Day].&[20160315]),
PARALLELPERIOD([Calendar].[Month], 3, [Calendar].[Day].&[20160315])
-- (...) How to generate this set automatically, using NumberOfMonths?
}
SELECT
{ Days } ON 0,
{ Quantity } ON 1
FROM [MyCube]
Any help would be appreciated.
It's an interesting problem, and though there is a solution, reading the MDX reference just led me down blind alleys.
Here's how you can get a set of the fifteenth day of each month:
WITH SET Months
AS
[Calendar].[Month].Members
SET FifteenthDays AS
GENERATE(
Months,
StrToSet('HEAD(DESCENDANTS(Months.Current,[Calendar].[Day]),1).Item(0).Lead(14)')
)
SELECT {} ON 0,
FifteenthDays ON 1
FROM TheCube
You can adjust this to suit your requirements, by filtering the initial named set "Months" using your date parameters.
Here's what's going on:
The GENERATE/StrToSet combination applies the MDX inside the quotes to each member of the first set ("Months")
The Current function is like CurrentMember, but applied to a set within Generate() brackets.
The DESCENDANTS function gets all the month's "children" at the Day level (I had to use this rather than .Children as in my cube there's an additional generation - Weeks - between Months and Days)
The HEAD function gets the first day in the month. (If your Time dimension leaf level is not sorted in date order, you may need to wrap the set in an ORDER function).
MDX doesn't automatically figure out that a singleton set (HEAD({},1) will trivially always return a singleton or the empty set) is a member, and you can apply member functions on it. So before applying Lead, I have to use the Item() function. I don't know why this function works, because according to the documentation it has a different purpose.
Lead(14) gives you the 15th day of the month, because the argument is 0-based.
The MDX approach №1 (a calculated member with sum aggregation):
WITH
MEMBER [Measures].[Quantity15] AS
SUM(
[Calendar].[Day].[Day].Members,
IIF(
Right([Calendar].[Day].CurrentMember.Properties('Key'),2) = "15",
[Measures].[Quantity],
NULL
)
)
SELECT
NON EMPTY { [Calendar].[Day].&[20100101]:[Calendar].[Day].&[20160315] } ON 0,
{ [Measures].[Quantity15] } ON 1
FROM [MyCube]
The MDX approach №2 (without new members, filtering the set):
SELECT
NONEMPTY(
{[Calendar].[Day].&[20100101]:[Calendar].[Day].&[20160315]},
IIF(
Right([Calendar].[Day].CurrentMember.Properties('Key'),2) = "15",
1,
NULL
)
) ON 0,
{ [Measures].[Quantity] } ON 1
FROM [MyCube]

MATLAB Extract all rows between two variables with a threshold

I have a cell array called BodyData in MATLAB that has around 139 columns and 3500 odd rows of skeletal tracking data.
I need to extract all rows between two string values (these are timestamps when an event happened) that I have
e.g.
BodyData{}=
Column 1 2 3
'10:15:15.332' 'BASE05' ...
...
'10:17:33:230' 'BASE05' ...
The two timestamps should match a value in the array but might also be within a few ms of those in the array e.g.
TimeStamp1 = '10:15:15.560'
TimeStamp2 = '10:17:33.233'
I have several questions!
How can I return an array for all the data between the two string values plus or minus a small threshold of say .100ms?
Also can I also add another condition to say that all str values in column2 must also be the same, otherwise ignore? For example, only return the timestamps between A and B only if 'BASE02'
Many thanks,
The best approach to the first part of your problem is probably to change from strings to numeric date values. In Matlab this can be done quite painlessly with datenum.
For the second part you can just use logical indexing... this is were you put a condition (i.e. that second columns is BASE02) within the indexing expression.
A self-contained example:
% some example data:
BodyData = {'10:15:15.332', 'BASE05', 'foo';...
'10:15:16.332', 'BASE02', 'bar';...
'10:15:17.332', 'BASE05', 'foo';...
'10:15:18.332', 'BASE02', 'foo';...
'10:15:19.332', 'BASE05', 'bar'};
% create column vector of numeric times, and define start/end times
dateValues = datenum(BodyData(:, 1), 'HH:MM:SS.FFF');
startTime = datenum('10:15:16.100', 'HH:MM:SS.FFF');
endTime = datenum('10:15:18.500', 'HH:MM:SS.FFF');
% select data in range, and where second column is 'BASE02'
BodyData(dateValues > startTime & dateValues < endTime & strcmp(BodyData(:, 2), 'BASE02'), :)
Returns:
ans =
'10:15:16.332' 'BASE02' 'bar'
'10:15:18.332' 'BASE02' 'foo'
References: datenum manual page, matlab help page on logical indexing.

MDX Group & Count

I'm having the below MDX Query
WITH
MEMBER Measures.Improvement AS
[Measures].[School Evaluation]
-
(
[Measures].[School Evaluation]
,[Cycle].[Name].CurrentMember.PREVMEMBER
)
MEMBER Measures.PreviousEvaluation AS
(
[Measures].[School Evaluation]
,[Cycle].[Name].CurrentMember.PREVMEMBER
)
SELECT
Measures.Improvement ON COLUMNS,
Filter (
{ [Cycle].[Name].[Name].ALLMEMBERS }
* { [School].[Name En].[Name En].ALLMEMBERS }
, Measures.PreviousEvaluation > 0
AND
[Measures].[School Evaluation] > 0
)
ON ROWS
FROM [SchoolCube];
This code generates the below output
Now what I need is to count the occurrence of Improvement "-2,-1,0,..." across all the schools So I have something like this
How Can I achieve this?
Thanks,
You have to add another dimension "Improvement" that holds possible values for either a fixed range, e.g. -10..+10 or you build the range dynamically based on your data.
Add a second measure group to the cube based on that dimension table and create a measure "Improvement base", that sums the improvement value. This is a helper measure to simplify the following steps.
Now you can create a new calculated measure:
CREATE MEMBER CURRENTCUBE.[Measures].[Count Improvements] AS
SUM(IIF([Measures].[Improvement] = [Measures].[Improvement base], 1, 0));
Maybe you have to scope the All-member of the Improvement dimension to sum the children.

Functions within accumarray

If I have a column of dates and a column of data, I use this code to find the cumulative sum of the data for each of the dates, as found in the third column:
orgcumulative=cell2mat(accumarray(day,data,[],#(x){cumsum(x)}));
k=orgcumulative==0;
CVD=orgCVD;
CVD(k)=[];
31,3,3
31,2,5
31,1,6
31,5,11
07,2,2
07,3,4
07,4,9
07,2,11
07,3,14
07,5,19
07,3,22
07,1,23
07,1,24
07,2,26
07,3,29
30,5,5
06,4,4
Now I want to divide each data point within a day by the sum of the data within that day. For example:
31,3,3,3/11
31,2,5,2/11
31,1,6,1/11
31,5,11,5/11 <-- 11 is the sum of data for the 31 date
07,2,2,2/29
07,3,4, %and so on...
07,4,9,
07,2,11,
07,3,14,
07,5,19,
07,3,22,
07,1,23,
07,1,24,
07,2,26,
07,3,29, <-- 29 is the sum of data for the 07 date
30,5,5,1
06,4,4,1
If I try:
fractions=cell2mat(accumarray(day,data,[],#(x){ data/sum(x) }));
This will divide the entire second column by each of the sums. Is there a way to restrict this so the division only happens for the members of the second column within each day?
Would it not be easier to accumulate the total for each day using accumarray and then use the day array as an index when accessing the accumarray output, like so:
total = accumarray(day, data); % equivalent to accumarray(day, data, [], #sum)
fractions = data ./ total(day);

Resources