SQL to MDX Where IN clause - ssas

I have a situation where I need to formulate an MDX query.The corresponding SQL query would look something like:
SELECT no_of_downloads
FROM table_1
WHERE project_code IN ('abc', 'def', 'ghi' , .....)
I have the following MDX query formulated but i can only use it for one project code at a time.
SELECT
[Measures].[#Activity] ON COLUMNS
,Filter
(
[Organisation Dimension].[Txt Project Code].MEMBERS
,
[Organisation Dimension].[Txt Project Code].CurrentMember.Name = 'KM_BNG'
) ON ROWS
FROM [Activity Cube]
WHERE
(
[Activity Dimension].[Txt Activity Name].&[Download]
,[System Dimension].[Txt System Name].&[KShop] //ENTER CODE HERE//
,[Time Dimension].[Fiscal Hierarchy].[Fiscal Half Year Name].&[2014-04-01T00:00:00]
);
How to add more project codes in the list?

or if you're really keen to use the WHERE clause then just move the SET created by FrankPI into the WHERE clause.
The WHEREclause is conceptually an axis and as a rule of MDX is that the same hierarchy cannot be placed on more than one axis you will need to move it from ROWS like this:
SELECT
[Measures].[#Activity] ON 0
FROM [Activity Cube]
WHERE
(
[Activity Dimension].[Txt Activity Name].&[Download]
,[System Dimension].[Txt System Name].&[KShop]
,{
[Organisation Dimension].[Txt Project Code].[KM_BNG],
[Organisation Dimension].[Txt Project Code].[other name],
[Organisation Dimension].[Txt Project Code].[third name]
}
,[Time Dimension].[Fiscal Hierarchy].[Fiscal Half Year Name].&[2014-04-01T00:00:00]
);
In the extreme case where you have 50 members of the hierarchy [Organisation Dimension].[Txt Project Code] that you want to include then it might be better managed in the cube script. You could create a set [myTxtProjectCodes] and then the MDX would be a lot simpler:
SELECT
[Measures].[#Activity] ON 0
FROM [Activity Cube]
WHERE
(
[Activity Dimension].[Txt Activity Name].&[Download]
,[System Dimension].[Txt System Name].&[KShop]
,{
[myTxtProjectCodes]
}
,[Time Dimension].[Fiscal Hierarchy].[Fiscal Half Year Name].&[2014-04-01T00:00:00]
);

You do not need filters, you just can enumerate the members in the ON ROWS clause in curly braces:
SELECT [Measures].[#Activity]
ON COLUMNS ,
{
[Organisation Dimension].[Txt Project Code].[KM_BNG],
[Organisation Dimension].[Txt Project Code].[other name],
[Organisation Dimension].[Txt Project Code].[third name]
}
ON ROWS
...

Related

Performance issue when converting MDX to DAX queries

I have a MDX query which I want to convert to DAX to improve performance, however the result is not as expected, MDX took 11 secs to complete while DAX was 34 secs. any suggestion to improve the DAX query
MDX Query:
SELECT
{
[Measures].[Internet Total Sales]
} ON COLUMNS,
ORDER(
NONEMPTY
(
{
[Product].[Model Name].[Model Name].AllMembers *
[Product].[Product Line].[Product Line].AllMembers *
[Product].[Product Name].[Product Name].AllMembers *
[Customer].[First Name].[First Name].AllMembers *
[Customer].[Last Name].[Last Name].AllMembers
},
{
[Measures].[Internet Total Sales]
}
),
[Product].[Model Name].CurrentMember.MemberValue, ASC
) ON ROWS
FROM [Model]
DAX Query:
EVALUATE
CALCULATETABLE
(
FILTER
(
SUMMARIZE
(
CROSSJOIN('Product', 'Customer'),
[Model Name],
[Product Line],
[Product Name],
[First Name],
[Last Name],
"Internet Total Sales",
[Internet Total Sales]
),
NOT ISBLANK([Internet Total Sales])
)
)
ORDER BY [Model Name] ASC
Thank you.
EVALUATE
SUMMARIZECOLUMNS(
'Product'[Model Name],
'Product'[Product Line],
'Product'[Product Name],
'Customer'[First Name],
'Customer'[Last Name],
"Internet Total Sales", [Internet Total Sales]
)
ORDER BY 'Product'[Model Name]

Access/SQL Cumulative Query wth GroupBy

I need a query that basically improves upon a query I already have. My original post was here: Access Cumulative Total by Date
The existing query is a running sum of the energy capacity online as of the end of the year. I need one that makes the same one but broken out by project type, preferably in a crosstab format.
The project capacity and online date is stored in the Projects table and the Alternative Energy Type that I need the table to be grouped by is in a different table, Project Types, and the two are related through a type ID.
I'm not very good with SQL, so I've been trying to just add in the Project Types table from the Access Query Builder, but just adding in another groupby column with the Alternative Energy Type
Original:
SELECT Year(p.[Online Date]) AS yr, (SELECT SUM(p2.[System Size AC])
FROM Projects as p2
WHERE YEAR(p2.[Online Date]) <= YEAR(p.[Online Date])
) AS running_sum
FROM Projects AS p
GROUP BY Year([Online Date]);
Modified (wrong):
SELECT Year(p.[Online Date]) AS yr, (SELECT SUM(p2.[System Size AC])
FROM Projects as p2
WHERE YEAR(p2.[Online Date]) <= YEAR(p.[Online Date])
) AS running_sum, [Project Types].[Alternative Energy Type]
FROM [Project Types] INNER JOIN Projects AS p ON [Project Types].[Type ID] = p.[Project Type]
GROUP BY Year([Online Date]), [Project Types].[Alternative Energy Type];
The results of the modified query just show the total yearly running sum with the Alterntaive Energy Types next to them. This isn't correct because it's just showing the same total over and over, nothing is broken out.
I need it to be broken out so that it answers the question "How much rooftop solar did we have as of 12/31/2015, 12/31/2016, etc and how much offsite wind did we have as of 12/31/2015, 12/31/2016, etc"
You need to add an equality to the correlated subquery by grouping field, Alternative Energy Type:
SELECT t.[Alternative Energy Type],
YEAR(p.[Online Date]) AS yr,
(SELECT SUM(subp.[System Size AC])
FROM Projects subp
INNER JOIN [Project Types] subt
ON subt.[Type ID] = subp.[Project Type]
WHERE YEAR(subp.[Online Date]) <= YEAR(p.[Online Date])
AND subt.[Alternative Energy Type] = t.[Alternative Energy Type]
) AS running_sum
FROM Projects p
INNER JOIN [Project Types] t
ON t.[Type ID] = p.[Project Type]
GROUP BY t.[Alternative Energy Type],
YEAR(p.[Online Date]);
For crosstab, first run a make-table action query since the running sum calculation will cause issues
SELECT *
INTO RunningSumTbl
FROM RunningSumQ
Then run the crosstab:
TRANSFORM Sum(q.running_sum) AS SumOfRunningSum
SELECT r.[Alternative Energy Type]
FROM RunningSumTbl r
GROUP BY r.[Alternative Energy Type]
PIVOT r.[yr];
Use PIVOT clause to subset and order columns:
PIVOT r.[yr] IN (2019, 2018, 2017, 2016, 2015)

Excluding dimension members from the measure calculation

I am not an MDX expert, I have this simplified query:
WITH MEMBER [Measures].[SalesCalc] AS
(
[Time Calculations].[Aggregation].&[4]
,[Measures].[Sales]
)
SELECT
[Measures].[SalesCalc]
ON 0
,{
[Product].[Product Source].[Product Source] - [Product].[Product Source].&[2]
} ON 1
FROM [Cube]
Which calculates my measure (from existing measure and pre-calculated aggregation) and shows all product sources except one particular source.
My goal is to show all the sources, the &[2] source should be there but the measure value for it should be NULL.
So I'm trying to get something like:
WITH MEMBER [Measures].[SalesCalc] AS
(
[Time Calculations].[Aggregation].&[4]
,[Measures].[Sales]
)
SELECT
[Measures].[SalesCalc] //but for [Product].[Product Source].&[2] this is NULL
ON 0
,
[Product].[Product Source].[Product Source] ON 1
FROM [Cube]
I seem to be unable to add the "do not calculate for product source &[2]" in measure and I cannot use the product source hierarchy on rows when I do a select since its already used on columns.
Any ideas?
Maybe try using IIF
WITH
MEMBER [Measures].[SalesCalc] AS
IIF(
[Product].[Product Source].CURRENTMEMBER
IS [Product].[Product Source].[Product Source].&[2]
,NULL
(
[Time Calculations].[Aggregation].&[4]
,[Measures].[Sales]
)
)
SELECT
[Measures].[SalesCalc] ON 0
,[Product].[Product Source].[Product Source] ON 1
FROM [Cube];

MDX return last month of every year

I am trying to create a set to return the value of the last month that contains data for each year.
For example if I would put year on the rows
2011,2012,2013,2014 would all contain data for December.
2015 would contain data for June of 2015.
I can't seem to get anything but the latest month to return. I figure it is because of my tail statement, but I'm not sure how to fix it.
CREATE SET [Last Statement Month] AS
Tail(
nonempty(
Descendants(
[Date].[Calendar].currentmember
,[Date].[Calendar].[Month]
),
[Measures].[Sale Amount]
), 1);
I also tried to get the last day of each month, but when I use this with the year on the rows nothing shows up.
GENERATE(
{
Openingperiod([Date].[Calendar].[Month]):ClosingPeriod([Date].[Calendar].Month)
},
{[Date].[Calendar].CurrentMember.Lastchild}
);
I'm currently away from AdvWrks so unable to test. Does the following help?
CREATE SET [Last Statement Month] AS
TAIL(
NONEMPTY(
EXISTING ([Date].[Calendar].[Month].MEMBERS)
,[Measures].[Sale Amount]
)
);
(If this approach works) Performance is apparently better if EXISTING is performed last:
CREATE SET [Last Statement Month] AS
TAIL(
EXISTING
NONEMPTY(
[Date].[Calendar].[Month].MEMBERS
,[Measures].[Sale Amount]
)
);
Looks like the above isn't going to work. I've added an alternative in the following which maybe is more what you're looking for:
WITH
DYNAMIC SET [Last Statement Month] AS
Tail
(
NonEmpty
(
(EXISTING
[Date].[Calendar].[Month].MEMBERS)
,[Measures].[Internet Sales Amount]
)
)
MEMBER [Measures].[x] AS
[Last Statement Month].Item(0).Item(0).Member_Caption
MEMBER [Measures].[Lst mth with data] AS `<<<<maybe something like this helps?
Max
(
(EXISTING
[Date].[Calendar].[Month].MEMBERS)
,IIF
(
[Measures].[Internet Sales Amount] = 0
,NULL
/*,[Date].[Calendar].CurrentMember.Member_Caption*/ //<<WRONG PROPERTY USED
,[Date].[Calendar].CurrentMember.MemberValue //<<should help!!
)
)
SELECT
{[Measures].[Lst mth with data],[Measures].[x]} ON 0
,[Date].[Calendar].[Calendar Year] ON 1
FROM [Adventure Works];
Results in this:
After Edit returns this:

how to determine which date hierarchy a user is drilling through

I am trying to implement a calculation dimension along the lines of the DateTool mechanism as outlined in the Expert Cube Development book by Chris Webb et al.
The issue is that, like most organizations, we have the need to report by both fiscal and calendar hierarchies, and based on multiple dates in our transaction table.
I would dearly love to be able to define one calculation dimension which redefines which time dimension and which calendar it uses based on which time dimension and hierarchy the user has chosen.
Here is a sample bit of code:
( [Time Calculations].[Calculation].[Year to Date] )
=
Sum(PeriodsToDate([Time Order Date].[Fiscal Date].[Fiscal Year Name],
[Time Order Date].[Fiscal Date].CurrentMember
),
[Time Calculations].DefaultMember
)
I would very much like to rewrite this as:
( [Time Calculations].[Calculation].[Year to Date] )
=
case
when user is viewing using the Order Date, Fiscal Calendar then
Sum(PeriodsToDate([Time Order Date].[Fiscal Date].[Fiscal Year Name],
[Time Order Date].[Fiscal Date].CurrentMember
),
[Time Calculations].DefaultMember
)
when user is viewing using the Ship Date, Fiscal Calendar then
Sum(PeriodsToDate([Time Ship Date].[Fiscal Date].[Fiscal Year Name],
[Time Ship Date].[Fiscal Date].CurrentMember
),
[Time Calculations].DefaultMember
)
when user is viewing using the Order Date, Calendar hierarchy then
Sum(PeriodsToDate([Time Order Date].[Calendar].[Year Name],
[Time Order Date].[Date].CurrentMember
),
[Time Calculations].DefaultMember
)
when user is viewing using the Ship Date, Calendar hierarchy then
Sum(PeriodsToDate([Time Ship Date].[Date].[Year Name],
[Time Ship Date].[Date].CurrentMember
),
[Time Calculations].DefaultMember
)
else null end
Is this possible?
You could try to insert following into your cube script. This should be aware of any Year levels no matter whether they are used on an axis or in a subselect.
This code uses the fact that dynamic sets are aware of subselects. In addition to that the keyword Existing is used in the IIF so that the calculation also knows about the hierarchies used in the WHERE clause or an Axis.
The Head function is there for performance reasons. You just need to know if at least 1 member of the dimensions is selected. There is no need to count all of them.
The script returns NULL when none of the required hierarchies are selected.
CREATE HIDDEN DYNAMIC SET CURRENTCUBE.[OrderDateFiscalYearAll]
AS [Time Order Date].[Fiscal Date].[Fiscal Year Name].MEMBERS;
CREATE HIDDEN DYNAMIC SET CURRENTCUBE.[OrderDateCalendarYearAll]
AS [Time Order Date].[Calendar].[Year Name].MEMBERS;
CREATE HIDDEN DYNAMIC SET CURRENTCUBE.[ShipDateFiscalYearAll]
AS [Time Ship Date].[Fiscal Date].[Fiscal Year Name].MEMBERS;
CREATE HIDDEN DYNAMIC SET CURRENTCUBE.[ShipDateCalendarYearAll]
AS [Time Ship Date].[Calendar].[Year Name].MEMBERS;
Scope([Time Calculations].[Calculation].[Year to Date]);
This = IIF(Count(Head(Existing [OrderDateFiscalYearAll], 1)) > 0
,/* Insert OrderDateFiscalYear calculation here */
,IIF(Count(Head(Existing [OrderDateCalendarYearAll], 1)) > 0
,/* Insert OrderDateCalendarYear calculation here */
,IIF(Count(Head(Existing [ShipDateFiscalYearAll], 1)) > 0
,/* Insert ShipDateFiscalYear calculation here */
,IIF(Count(Head(Existing [ShipDateCalendarYearAll], 1)) > 0
,/* Insert ShipDateCalendarYear calculation here */
,NULL))))
End Scope;