How to calculate average on two dimensions in MDX - mdx

I'm trying to convert the following SQL query into a calculated member in my SSAS cube.
SELECT ActionKey, AVG(1.0 * Days) AS AverageDays
FROM( SELECT ActionKey, UserKey, COUNT(DISTINCT DateKey) AS Days
FROM [TEST].[dbo].[FactActivity]
GROUP BY ActionKey, UserKey) a
GROUP BY ActionKey
How do I do this in MDX? I tried the following but it's giving me wrong result
IIF([Measures].[Dim User Count] = 0, 0 , [Measures].[Dim Date
Count]/[Measures].[Dim User Count])
In my cube, I have two derived measures . "Dim Date Count" which is count of rows in DimDate table and "Dim User Count" which is count of row of DimUser table. Both have many-many relationship with other dimensions of the cube, so i can calculate the distinct days and users easily.

This worked
AVG([Users].[User Key].[User Key], [Measures].[DATE COUNT])

(not a solution but maybe helps)
Are the two measures that you've created giving the results you expect? If you run the equivalent of the following against [YourCube] is it just the new measure [Measures].[AverageDays] that is wrong?
SELECT
NON EMPTY
{
[Measures].[AverageDays]
,[Measures].[Dim Date Count]
,[Measures].[Dim User Count]
} ON COLUMNS
,NON EMPTY
{
[Action].[Action].MEMBERS
*
[Date].[Calendar].[Month].ALLMEMBERS
} ON ROWS
FROM [YourCube];

Related

SSAS MDX sum up on memberships in date hierarchies?

In a cube that contains memberships of a club, I have a column MembersInOut in my fact-table which holds when a member joined the club (Value = 1) and leaving (value = -1). The Club started jan 1. 2000. so no members before that date.
Now to know the current number of members on a specific date I can do this:
CREATE MEMBER CURRENTCUBE.[Measures].[Calculated MembersOfTheClub]
AS
Sum(
{[Date Dim].[Date].&[2000-01-01T00:00:00]:
[Date Dim].[Date].currentmember},
[Measures].[MembersInOut]
)
This works fine on the actuel date, but how to make this work on a date hierarchie [Year-Month-day] ?
Thanks
You could create Y-M-D hierarchy, then use expression like below
with member[Measures].[S1] AS
sum(
{NULL:[Date].[Calendar Date].CurrentMember}
, [Measures].[Internet Sales Count])
select nonempty ([Date].[Calendar Date].members) on rows, nonempty ({[Measures].[S1],[Measures].[Internet Sales Count]}) on columns from [Analysis Services Tutorial]
Zoe

How do I build a MDX query that considers only facts that happened in the last 10 days of February?

I have a fact table that has a time dimension, which contains year, month, day and hour.
I was able to find ways to filter things that happened in a given day, or month (simple where/filter by the desired level). But I would like to create an MDX query that filter the results so my cube has information about the facts recorded in the last 10 days of febraury.
Is there anyway I can do it?
Assuming you have all the days of February in your cube, you could use a set inside there WHERE clause.
Something like this..
WHERE ([Date].Month)
Supposing you have a Year-Month-Day-Hour hierarchy in place and there may be some dates missing
Select....... on COLUMN,
....... ON ROWS
FROM ....
WHERE
({[Time].[Month].&[Feb 2015].LastChild.LAG(10) : [Date].[Month].&[Feb 2015].LastChild})
If no dates are missing in the date dim,
select ... ON COLUMNS,
... ON ROWS
FROM ...
WHERE
({[Time].[Date].&[02/19/2015] : [Date].[Date].&[02/28/2015]})
If you want the sales for last 10 days of Feb for every year:
SELECT Measures.Sales ON COLUMNS,
Products.Products.MEMBERS ON ROWS
FROM
(
SELECT
generate //This would build the set for the last 10 days of Feb for every year
(
[Time].[Year].[All].children,
TAIL //This returns the last 10 days of february(second month)
(
[Time].[Year].CURRENTMEMBER.FIRSTCHILD.LEAD(1).CHILDREN,
10
)
) ON COLUMNS
FROM YourCube
)
Just as some extra info - if you want a "rolling" 10 day sum or 10 day average then code similar to the following is a possible approach:
WITH
MEMBER [Measures].[Sum 10] AS
Sum
(
LastPeriods
(10
,[Date].[Calendar].CurrentMember
)
,[Measures].[Internet Order Count]
)
MEMBER [Measures].[MovAvg 10] AS
Avg
(
LastPeriods
(10
,[Date].[Date].CurrentMember
)
,[Measures].[Internet Order Count]
), format_string = "#.000"
SELECT
{
[Measures].[Internet Order Count]
,[Measures].[Sum 10]
,[Measures].[MovAvg 10]
} ON 0
,Descendants
(
[Date].[Calendar].[Month].&[2006]&[2]
,[Date].[Calendar].[Date]
) ON 1
FROM [Adventure Works];
It returns data like the following:

Is COUNTDISTINCT base measure faster than calculated distinct measure?

I have a fact table and dimension table that look like this
​Fact {DateKey,UserKey,ActionKey,Action Count}
I have a user dimension table that looks like this
DimUser {UserKey,Name,IsActive}
and a date dimension table that looks like this
DimDate { DateKey, Week, Year}
I have a physical distinct count measure on the DateKey column on the measure group based of the fact table..lets call it "DATE COUNT"
Now I want to have a calculated measure called "DAILY ACTIVE USERS" which will looks like this
[IsDailyActive] = IIF([Measures].[DATE COUNT] >= 21, 1, 0)
[Daily Active Users] = SUM([Dim User].[User Key].[User Key].Members, [Measures].[IsDailyActive])
There is also another way to solve this problem w/o using the physical distinct count measure as follows
[HasAction] = IIF([Measures].[Action Count] > 1, 1, 0)
[DATE COUNT] = SUM([Dim Date].[DATE KEY].[DATE KEY].Members, [Measures].[HasAction])
[IsDailyActive] = IIF([Measures].[DATE COUNT] >= 21, 1, 0)
[Daily Active Users] = SUM([Dim User].[User Key].[User Key].Members, [Measures].[IsDailyActive])
But I'm afraid the calculated measure will be slower than the physical distinct count measure that is calculated at processing time instead of at query time. Any thoughts of which will be better performing? My fact table has billion rows!

calculating month salary for an employee

I am working on my Database in MS Access 2010
and i Need to build a query to Calculate the month salary for each Employee
it goes like this :
Input from user , which Year
Input from user again , which Month
Show Every Employee's Salary for the Input date
There are 2 Tables in the Query : Shifts , Employees
Shifts has a field for EmployeeID and a field for Day
Day field format is : Short Date
The problem is i don't know how to access the Month and the Year only !
I know that this is completely wrong , but i wanna do something like this:
SELECT
FROM EmployeesTBL INNER JOIN ShiftsTBL ON EmployeesTBL.EmployeeID = ShiftsTBL.EmployeeID
WHERE
Year(ShiftsTBL.Day)=[Enter Year]
AND
Month(ShiftsTBL.Day)=[Enter Month]
;
What do i need to write after SELECT to get the Sum of all Shifts and divide it by number of days the emp worked
Note : in the Shifts Table , i have EntryDate and ExitDate for every shift
Access has a bunch of built in date functions. I believe Month(date) and Year(date) will give you what you need.
Something like
SELECT EmpName
FROM Employees, Shifts
WHERE Employees.EmployeeID = Shifts.EmployeeID
AND
Month(Shifts.Day) = INPUT2.VALUE
AND
Year(Shifts.Day) = INPUT1.VALUE
should get you what you want!
EDIT: Aggregation: how this works will depend on how your database is set up. I think I understand you want to sum the hours worked and divide by the number of days?
If so, you will use Sum() and Count(). And you will Group By EmployeeID
SELECT Sum(Shifts)/Count(DaysWorked) AS SumDividedByCount
FROM EmployeesTBL INNER JOIN ShiftsTBL
ON EmployeesTBL.EmployeeID = ShiftsTBL.EmployeeID
WHERE
Year(ShiftsTBL.[Day])=[Enter Year]
AND
Month(ShiftsTBL.[Day])=[Enter Month]
GROUP BY EmployeeID
I used the WHERE clause because I think the results need to be filtered before they're grouped. If the results needed to be filtered after they were grouped, the HAVING clause would be used (and would go AFTER the GROUP BY)

How to get data from last days

I'm a newcomer to SQL MDX and don't know exactly how to achieve this.
I need to get data from my cube for the last X days from the last available data.
The following is my code:
SELECT { [Measures].[Fact Stays Count], [Measures].[Time Spent] } ON COLUMNS,
NON EMPTY { ( [Dim Locals].[Local Description].[Local Description].ALLMEMBERS * [FK Date].[Date].[Date] ) } ON ROWS
FROM
(
select { TAIL(FILTER([FK Date].[Date].MEMBERS, NOT ISEMPTY([FK Date].[Date].CURRENTMEMBER)),30) } ON COLUMNS
FROM (
SELECT ( STRTOSET(#userId, CONSTRAINED) ) ON COLUMNS
FROM [DW]
)
)
The problem is the query returns the last 30 days where data exists, not the last 30 consecutive calendar days.
How can I change the query to get the results I want?
Try this. The only thing I changed is the select with the dates in it. Instead of asking for the last 30 days where there is data for the measures, I'm asking for the last day where there is data for the measures, getting that last item and then doing the lag of 29 days for the beginning of the date range and then without the lag (to the last day with data) for the end of the date range.
SELECT { [Measures].[Fact Stays Count], [Measures].[Time Spent] } ON COLUMNS,
NON EMPTY { ( [Dim Locals].[Local Description].[Local Description].ALLMEMBERS * [FK Date].[Date].[Date] ) } ON ROWS
FROM
(
select { TAIL(FILTER([FK Date].[Date].MEMBERS, NOT ISEMPTY([FK Date].[Date].CURRENTMEMBER)),1).item(0).lag(29): TAIL(FILTER([FK Date].[Date].MEMBERS, NOT ISEMPTY([FK Date].[Date].CURRENTMEMBER)),1).itm(0)} ON COLUMNS
FROM (
SELECT ( STRTOSET(#userId, CONSTRAINED) ) ON COLUMNS
FROM [DW]
)
)
Be aware that the way you have the query now will return the last day where there is data for both measures. If those two measures don't line up it might not provide what you want. For instance, if there is data through Dec 30 2013 on Fact Stays Count and data through Jan 5 2014 on Time Spent, it would return Dec 30 2013. If you want it to depend on both measures, you are good. If you want it to depend on one measures, you can switch it to be something like the below instead.
Tail(Filter([FK Date].[Date].[Date].MEMBERS.MEMBERS, [Measures].[Fact Stays Count] >0),1).item(0)