MDX - Using IIF to affect sets in a crossjoin - mdx

I have a crossjoin that looks like this
SELECT
{[Measures].[Respondent Count]} ON COLUMNS
,{
[Groups In Rows].[Group].ALLMEMBERS*
[Questions In Rows].[By ShortCode].[Option].ALLMEMBERS*
[Questions In Columns].[By ShortCode].[Option].ALLMEMBERS
} ON ROWS
FROM [cube]
I want to be able to dynamically remove the crossjoin on Groups In Rows according to a parameter so that in pseudo mdx we would have
SELECT
{[Measures].[Respondent Count]} ON COLUMNS
,
IIF(#UseGroups = "yes",
{ [Groups In Rows].[Group].ALLMEMBERS*
[Questions In Rows].[By ShortCode].[Option].ALLMEMBERS*
[Questions In Columns].[By ShortCode].[Option].ALLMEMBERS
},
{
[Questions In Rows].[By ShortCode].[Option].ALLMEMBERS*
[Questions In Columns].[By ShortCode].[Option].ALLMEMBERS
} ON ROWS
FROM [Cube]
Is anything like this possible?

Since you use the #UseGroups notation, I'm assuming you're refering to a Reporting Services parameter.
You can use an expression for the query, and construct the query in regards to the parameter:
="SELECT { [Measures].[Respondent Count] } ON COLUMNS, "
&" { "
& Iif(#UseGroups = "yes",
"[Groups In Rows].[Group].ALLMEMBERS*",
"[Groups In Rows].[Group].All")
&" [Questions In Rows].[By ShortCode].[Option].ALLMEMBERS* "
&" [Questions In Columns].[By ShortCode].[Option].ALLMEMBERS "
&" } ON ROWS "
&" FROM [Cube]"
You have to include the All member for the false branch of the Iif function, because of metadata problems.

Related

MDX Combine two queries

I need two join two queries, I tried with members but it didn't work. I am new to MDX, please let me know if there a way of doing this. Error is due to list in the calculated member.
SELECT NON EMPTY { [RR TYPE].[Item].[Item].ALLMEMBERS * [Measures].[Unit Value] } ON COLUMNS,
NON EMPTY { ([FFS].[FFSCD].[FFSCD].ALLMEMBERS) } ON ROWS
FROM [GLCube]
WHERE ( [Location].[Site Name].&[Sandbox]
, [LT DT].[DATE HIERARCHY].[YEAR].&[2010]
,-{ [Ledger].[ID].&[A1],[Ledger].[ID].&[A2] ,[Ledger].[ID].&[A3]} )
SELECT NON EMPTY { [RT TYPE].[Item].[Item].ALLMEMBERS * [Measures].[Price Value] } ON COLUMNS,
NON EMPTY { ([FFS].[FFSCD].[FFSCD].ALLMEMBERS) } ON ROWS
FROM (SELECT [CCTYPE].[Desc].&[FCD] ON COLUMNS
FROM [GLCube])
WHERE ( [Location].[Site Name].&[Sandbox]
, [LT DT].[DATE HIERARCHY].[YEAR].&[2010])
Combined query
WITH MEMBER [Measures].[Unit Value]] AS
(-{[Ledger].[ID].&[A1],[Ledger].[ID].&[A2] ,[Ledger].[ID].&[A3]},[Measures].[Unit Value])
MEMBER [Measures].[Price Value] AS
( [CCTYPE].[Desc].&[FCD],[Measures].[Price Value] )
SELECT NON EMPTY {[Measures].[Unit Value],[Measures].[Price Value]} ON COLUMNS,
NON EMPTY { ([FFS].[FFSCD].[FFSCD].ALLMEMBERS} ON ROWS
FROM [GLCube]
WHERE ( [Location].[Site Name].&[Sandbox]
, [LT DT].[DATE HIERARCHY].[YEAR].&[2010])
Expected Output
WITH
MEMBER [Measures].[Filtered Unit Value] as
Aggregate(
-{ [Ledger].[ID].&[A1],[Ledger].[ID].&[A2] ,[Ledger].[ID].&[A3]},
[Measures].[Unit Value]
)
SELECT NON EMPTY
{
[RR TYPE].[Item].[Item].ALLMEMBERS
* {[RT TYPE].[Item].[All]}
* { [CCTYPE].[Desc].[All]}
* [Measures].[Filtered Unit Value]
}
+
{
{[RR TYPE].[Item].[All]}
* [RT TYPE].[Item].[Item].ALLMEMBERS
* { [CCTYPE].[Desc].&[FCD]}
* [Measures].[Price Value]
}
ON COLUMNS,
NON EMPTY { ([FFS].[FFSCD].[FFSCD].ALLMEMBERS) } ON ROWS
FROM [GLCube]
WHERE ( [Location].[Site Name].&[Sandbox]
, [LT DT].[DATE HIERARCHY].[YEAR].&[2010]
)

Add a column to the MDX Query with a tuple

I have an MDX Query running on the SSAS cube that returns lots of object codes and the period balances for them. I was able to add multiple period balances by using a crossjoin on the rows, however I would like to add one more row with the period end balance for the last fiscal period, and can't seem to figure out a way to do it.
The initial query is
select
non empty
{
[Object Code].[Object Code Number].[Object Code Number]
*
[Object Code].[Object Code Description].[Object Code Description]
*
[Object Code Pathing 1E 1R].[1E_R1 Value].[1E_R1 Value]
*
[Object Code Pathing 1E 1R].[1E_R2 Value].[1E_R2 Value]
*
[Object Code Pathing 1E 1R].[1E_R3 Value].[1E_R3 Value]
*
[Object Code Pathing 1E 1R].[1E_R4 Value].[1E_R4 Value]
}
on rows,
{
[Measures].[Current Period Balance]
}
*
{
[Date].[Fiscal].[Fiscal Period].&[2016]&[1]:[Date].[Fiscal].[Fiscal Period].&[2016]&[7]
}
on columns
from [Finance]
and when I am trying to add one more column
select
non empty
{
[Object Code].[Object Code Number].[Object Code Number]
*
[Object Code].[Object Code Description].[Object Code Description]
*
[Object Code Pathing 1E 1R].[1E_R1 Value].[1E_R1 Value]
*
[Object Code Pathing 1E 1R].[1E_R2 Value].[1E_R2 Value]
*
[Object Code Pathing 1E 1R].[1E_R3 Value].[1E_R3 Value]
*
[Object Code Pathing 1E 1R].[1E_R4 Value].[1E_R4 Value]
}
on rows,
{
[Measures].[Balance At Period End]
*
[Date].[Fiscal].[Fiscal Period]&[2016]&[7]
},
{
[Measures].[Current Period Balance]
}
*
{
[Date].[Fiscal].[Fiscal Period].&[2016]&[1]:[Date].[Fiscal].[Fiscal Period].&[2016]&[7]
}
on columns
from [Finance]
I get the
Parser: The statement dialect could not be resolved due to ambiguity. error
and if I add it like
{
[Measures].[Current Period Balance],
[Measures].[Balance At Period End]
}
*
{
[Date].[Fiscal].[Fiscal Period].&[2016]&[1]:[Date].[Fiscal].[Fiscal Period].&[2016]&[7]
}
on columns
I get Period end Balances for all periods, and this is not needed in the report, I only need the Balance at Period End for the very last period
Here is your first piece of troublesome code:
crossjoin (
[Measures].[Current Period Balance]
,{
[Date].[Fiscal].[Fiscal Period].&[2016]&[1]
,[Date].[Fiscal].[Fiscal Period].&[2016]&[2]
,[Date].[Fiscal].[Fiscal Period].&[2016]&[3]
}
), //<<1
crossjoin(
[Measures].[Balance At Period End]
,{[Date].[Fiscal].[Fiscal Period].&[2016]&[3]}
) on columns
from [Finance]
At point 1 you have closed the first crossjoin and then put a comma - this is a syntax error.
You could try moving that brace from 1 to the end of the statement:
crossjoin (
[Measures].[Current Period Balance]
,{
[Date].[Fiscal].[Fiscal Period].&[2016]&[1]
,[Date].[Fiscal].[Fiscal Period].&[2016]&[2]
,[Date].[Fiscal].[Fiscal Period].&[2016]&[3]
}
, //<<1
crossjoin(
[Measures].[Balance At Period End]
,{[Date].[Fiscal].[Fiscal Period].&[2016]&[3]}
)
) on columns //<<now closing initial crossjoin here
from [Finance]
Ok I just tested the above via the following and it is not a valid approach:
SELECT
CrossJoin
(
[Measures].[Internet Sales Amount]
,{
[Date].[Calendar].[Date].&[20060628]
,[Date].[Calendar].[Date].&[20060629]
}
,CrossJoin
(
[Measures].[Internet Order Quantity]
,{[Date].[Calendar].[Date].&[20060629]}
)
) ON COLUMNS
,[Product].[Product Categories].[All] ON ROWS
FROM [Adventure Works];
We get the following error:
Query (2, 3) The Measures hierarchy is used more than once in the
Crossjoin function.
You could switch to the following structure, creating a set of tuples. This does run:
SELECT
{
[Measures].[Internet Sales Amount]
*
{
[Date].[Calendar].[Date].&[20060628]
,[Date].[Calendar].[Date].&[20060629]
}
,(
[Measures].[Internet Order Quantity]
,{[Date].[Calendar].[Date].&[20060629]}
)
} ON COLUMNS
,[Product].[Product Categories].[All] ON ROWS
FROM [Adventure Works];
Result:

MDX Get UserName Where UserID

Here is my MDX query below:
SELECT
{
[Measures].[Amt Exrate]
,[Measures].[Comm Exrate]
} ON COLUMNS
,NonEmpty([AccSetting].[User N].[User N] * [Cur Log].[Cur Log ID].Children) ON ROWS
FROM [report]
WHERE
[AccSetting].[Ag ID].&[113];
http://i.stack.imgur.com/0yDHg.png
UserID =113 is a hierarchies and a want to get the userN of it
I want to return exactly UserName of UserID =113 on Rows. but I'm not sure how to do it.
If you just want the name and nothing else then this should do it:
SELECT
{} ON COLUMNS
,[AccSetting].[User N].[User N] ON ROWS
FROM [report]
WHERE
[AccSetting].[Ag ID].&[113];
If you want to turn the name into a measure then something like the following, with a custom measure should help:
WITH
MEMBER [Measures].[userName] AS
[AccSetting].[User N].CurrentMember.Member_Caption
SELECT
{} ON 0
,{
[Measures].[userName]
,[Measures].[Amt Exrate]
,[Measures].[Comm Exrate]
} ON 1
FROM [report]
WHERE
[AccSetting].[Ag ID].&[113];
To return the columns you mentioned in comment this should work:
SELECT
NON EMPTY
{
[Measures].[Amt Exrate]
,[Measures].[Comm Exrate]
} ON COLUMNS
,NON EMPTY
[AccSetting].[User N].[User N].MEMBERS
* [Cur Log].[Cur Log ID].MEMBERS
ON ROWS
FROM [report]
WHERE
[AccSetting].[Ag ID].&[113];
EDIT
Answer in this article:
Get hierarchies valuesName mdx
Try having this way:
with dynamic set UserN as
NonEmpty(
[AccSetting].[User N].[User N].members * [Cur Log].[Cur Log ID].Children
,
[AccSetting].[Ag ID].currentmember
*
{
[Measures].[Amt Exrate],
[Measures].[Comm Exrate]
}
)
SELECT
{
[Measures].[Amt Exrate]
,[Measures].[Comm Exrate]
} ON COLUMNS
,UserN ON ROWS
FROM [report]
WHERE
[AccSetting].[Ag ID].&[113];

Datatables server side processing and column alias

In Datatables using server side processing, is it possible to use column alias when specifying the columns?
At the moment this works fine with:
$aColumns = array( 'datetime','username', 'user_ip', 'company', 'action' );
but I would like to change the format of the date using date format in MySQL so, in effect, I want to use:
$aColumns = array( 'DATE_FORMAT(datetime, "%d/%m/%Y - %H:%i:%s") as newdate';'username'; 'user_ip';'company'; 'action' );
The problem is that the alias has a comma and the aColumns array is comma seperated so it breaks when later, for example, it comes to:
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
FROM $sTable
$sWhere
$sOrder
$sLimit
";
Is there a way I can use the alias rather than the original value? Even simply changing the select statement does not work as aColumns is used throughout the script hence it needs that value to be set correctly
Thanks
Yes. I actually just struggled with this issue myself. Because the JSON output is determined through counting the amount of columns in the array, and because of the imploding array, you have to add your column alias to $sQuery instead of the $aColumns array. So you'll actually have one less column in your $aColumns array than you'll need. For example, in mine, I needed an alias called total created from multiplying price and qty. So I put all my unaliased columns in the $aColumns array, like this:
$aColumns = array( 'purchaseID', 'dateOfOrder', 'productID', 'price', 'QTY');
But then, in the $sQuery string that concatenates all the things necessary to create the proper query string, I added my column alias between the implode and FROM. Don't forget to put a comma after the implode though, because it doesn't add it for you. The original $sQuery string looks like this:
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
FROM `$sTable`
$sWhere
$dateSql
$sOrder
$sLimit
";
But mine, with the column alias added, looks like this:
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
, `price` * `QTY` AS `total` FROM `$sTable`
$sWhere
$dateSql
$sOrder
$sLimit
";
Finally, the last thing you have to do is alter the actual JSON output to make sure your extra column is accounted for in the FOR loop at the end right before the json_encode, because it inserts items into the $row array, which is what becomes 'aaData' (the returned row data), based on how many columns you've specified in the $aColumns array, and because you left out any you've aliased, the count will be wrong, and you will get an error that looks something like 'requested unknown parameter from data source row'. The original FOR loop looks like this:
while ( $aRow = mysql_fetch_array( $rResult ) )
{
$row = array();
for ( $i=0 ; $i<count($aColumns) ; $i++ )
{
if ( $aColumns[$i] == "version" )
{
/* Special output formatting for 'version' column */
$row[] = ($aRow[ $aColumns[$i] ]=="0") ? '-' : $aRow[ $aColumns[$i] ];
}
else if ( $aColumns[$i] != ' ' )
{
/* General output */
$row[] = $aRow[ $aColumns[$i] ];
}
}
$output['aaData'][] = $row;
}
Like I said, this FOR loop works based off the COUNT of the $aColumns array, and since I've added an alias, it's going to cut my results short. It's not going to return the last element in the array containing the returned columns, so I'm going to alter the code to look like this:
for ( $i=0 ; $i<count($aColumns) + 1; $i++ )
{
if ($i < count($aColumns)){
if ( $aColumns[$i] == "version" )
{
/* Special output formatting for 'version' column */
$row[] = ($aRow[ $aColumns[$i] ]=="0") ? '-' : $aRow[ $aColumns[$i] ];
}
else if ( $aColumns[$i] != ' ' )
{
/* General output */
$row[] = $aRow[ $aColumns[$i] ];
}
}
else {
$row[] = $aRow['total'];
}
}
$output['aaData'][] = $row;
}
All I changed was the counter condition from $i<count($aColumns) to $i<count($aColumns) + 1, because my alias makes the column count one higher than what's in the array. And I've added a wrapping if-else that just says that if the counter, $i, is higher than the number of columns I've specified in the $aColumns array, then we've added all the columns in the array to the output data, so because I only added one extra alias column, then that means I can go ahead and just add that to the $row array, which contains all the output data from the returned rows.
You can actually add in as many aliased columns as you need, you just need to scale the code accordingly. Hope this helps!

How do you get the total rows in an MDX query to use for paging?

I am attempting to implement paging to large datasets in MDX (SSAS).
I have the following to retrieve paged data which works fine:
SELECT
{
[Measures].[Mesasure1],
[Measures].[Measure2]
} ON COLUMNS,
SUBSET
(
ORDER
(
{
(
[Item].[Category].ALLMEMBERS
)
}, NULL, BASC
), 10, 50 --10 = start index, 50 = returned roes
)
ON ROWS
FROM ( SELECT ( { [Time].[Date].&[2012-04-15T00:00:00]:[Time].[Date].&[2012-04-20T00:00:00] } ) ON COLUMNS
FROM [DataMartPerformance]
))
However I cannot for the life of me find anywhere on the internet that helps explain how to get the total rows available. Do I do it in a seperate query? If so how?
Or can I wrap it into this one query somehow?
Similar to how you'd do TSQL paging, you'll need to run another query to count the total elements. You may have to tinker with this depending on how you've done your original query, but I use something like:
WITH
MEMBER [Measures].[ElementCount] AS
{
NONEMPTY
(
{
[Item].[Category].ALLMEMBERS *
{ [Time].[Date].&[2012-04-15T00:00:00]:[Time].[Date].&[2012-04-20T00:00:00] }
},
{
[Measures].[Mesasure1],
[Measures].[Measure2]
}
)
}.COUNT
SELECT
{
[Measures].[ElementCount]
}
ON COLUMNS
FROM
[DataMartPerformance]
For filtering, you can do dimension filters by using an exists against your dimension attributes:
WITH
MEMBER [Measures].[ElementCount] AS
{
NONEMPTY
(
EXISTS
(
{
[Item].[Category].ALLMEMBERS *
{ [Time].[Date].&[2012-04-15T00:00:00]:[Time].[Date].&[2012-04-20T00:00:00] }
},
{
[Dimension].[Attribute].[FilterByThisAttribute]
}
),
{
[Measures].[Mesasure1],
[Measures].[Measure2]
}
)
}.COUNT
SELECT
{
[Measures].[ElementCount]
}
ON COLUMNS
FROM
[DataMartPerformance]
I haven't got to writing the measure value filters yet, I need to do that next for my own MDX paging constructor...
Please try this:
WITH
SET MySet As
(
NONEMPTY (
[AU Time Sale Hour].[Hour Key].[Hour Key]
* [Dim Country].[Country Key].[Country Key]
)
)
Member [Measures] .cnt AS MySet.Count
select [Measures] .cnt on Columns
from [Me Stats DW Fact Sales]
where (
{[Dim Visa].[Visa Key].&[2067],[Dim Visa].[Visa Key].&[2068] },
[AU Time Sale Date].[Date].&[20091120]:[AU Time Sale Date].[Date].&[20091125]
)