Search code examples
timecountmdxintervals

MDX query count Login occurences over time interval


Im puzzle as to how to build my fact and dimensions to procude the following results:

I want to count the number of occurences of logged people for each time interval.

In this case every 30 mins. It would look like this

Example: Person1 login at 10:05:00 and logout at 12:10:00
         Person2 login at 10:45:00 and logout at 11:25:00
         Person3 login at 11:05:00 and logout at 14:01:00

    TimeStart  TimeEnd     People logged

    00:00:00   00:30:00    0
    00:30:00   01:00:00    0
    ...
    10:00:00   10:30:00    1
    10:30:00   11:00:00    2
    11:00:00   11:30:00    3
    11:30:00   12:00:00    2
    12:00:00   12:30:00    2
    12:30:00   13:00:00    1
    13:00:00   13:30:00    1
    13:30:00   14:00:00    1
    14:00:00   14:30:00    0
    ...
    23:30:00   00:00:00    0

So i have a DimTime and DimDate table that contain hour, halfhour, quarterhour and i have a FactTimestamp table that has the following:

DateLoginID that points to DimDate dateID
DateLogoutID that points to DimDate dateID
TimeLoginID that points to DimTime timeID
TimeLogoutID that points to DimTime timeID

I'd like to know what kind of cube design i would need to achieve that?

Ive done it in sql if that can help:

    --Create tmp table for time interval
    CREATE TABLE #tmp(
        StartRange time(0),
        EndRange time(0),
    );
    --Interval set to 30 minutes
    DECLARE @Interval int = 30
    -- Example with @Date = 2017-07-27: Set starttime at 2017-07-27 00:00:00
    DECLARE @StartTime datetime = DATEADD(HOUR,0, @Date)
    --Set endtime at 2017-07-27 23:59:59
    DECLARE @EndTime datetime = DATEADD(SECOND,59,DATEADD(MINUTE,59,DATEADD(HOUR,23, @Date)))
    --Populate tmp table with the time interval. from midnight to 23:59:59
    ;WITH cSequence AS
    (
        SELECT
            @StartTime AS StartRange, 
            DATEADD(MINUTE, @Interval, @StartTime) AS EndRange
        UNION ALL
        SELECT
            EndRange, 
            DATEADD(MINUTE, @Interval, EndRange)

        FROM cSequence
        WHERE DATEADD(MINUTE, @Interval, EndRange) <= @EndTime
    )
    INSERT INTO #tmp SELECT cast(StartRange as time(0)),cast(EndRange as time(0)) FROM cSequence OPTION (MAXRECURSION 0);
    --Insert last record 23:30:00 to 23:59:59
    INSERT INTO #tmp (StartRange, EndRange) values ('23:30:00','23:59:59');

    SELECT tmp.StartRange as [Interval], COUNT(ts.TimeIn) as [Operators]
    FROM #tmp tmp

    JOIN Timestamp ts ON    
                                --If timeIn is earlier than StartRange OR within the start/end range                        
                                (CAST(ts.TimeIn as time(0)) <= tmp.StartRange OR CAST(ts.TimeIn as time(0)) BETWEEN tmp.StartRange AND tmp.EndRange)
                                AND
                                --AND If timeOut is later than EndRange OR within the start/end range                       
                                CAST(ts.[TimeOut] as time(0)) >= tmp.EndRange OR CAST(ts.[TimeOut] as time(0)) BETWEEN tmp.StartRange AND tmp.EndRange                      

    GROUP BY tmp.StartRange, tmp.EndRange
END

Really any kind of hint as to how to achieve it in mdx would be greatly appreciated.


Solution

  • Honestly, I wouldn't do it in MDX against that table structure. Even if you succeed in getting an MDX query that returns that value, and surely it can be done, it will most likely be tremendously complex and hard to maintain and debug, and will probably require multiple passes on the fact table to get the numbers, hurting performance.

    I think this is a clear cut case for a periodic snapshot table. Pick your granularity, but even at 1 min snapshots you get 1440 points of data per day for each tuple of all other dimensions. If your login/logout table is large you may need to decrease this to keep its size manageable. In the end, you get a table with time_id, count_of_logins, and whatever other keys you need to other dimensions, and the query you need is just a filter on which time periods you want (give me all hours of the day, but filter on only minutes 00 and 30 of each hour) and the count of total number of logged in users is trivial.