Skip to main content

Return of the data-geek. EPM OLAP Cube Custom Measures

I thought i'd put rogether a quick post on Cube customisation, as this is something that I am constantly asked about. Now I am not an MDX expert at all, but there are some useful results you get from some pretty simple MDX expressions.

Firstly, custom measures are done in the OLAP Cube Database Management section of the Project Web App Server Settings page.  Hightlight the cube you want to customise and then click Configure.

Once in this section you need to scroll down to the bottom and decide which cube you want to add the measure to in the OLAP database.  Generally in most scenarios, the Portfolio Analyser cube is the best target, depending on the data you wish to interrogate.  Once the cube is selected, click Insert.

OK, so you've got a decent OLAP report (in excel, PerformancePoint Services or the like) showing data by month, but you been asked for a nice S-curve report showing Baseline, Work and Actual Work on a cumulative curve.  As with all useful things, its short but complex query that is needed.

This example would give you a cumulative WORK calculation, specifically from the earliest date possible.
>  sum(periodstodate([time].[(all)]),[measures].[Work])

This example is a little more simple and would do the same but only over this year
>  sum(periodstodate([time].[Year]),[measures].[Work])

This example is the associated Actual Work S-Curve but allows for there to be NULL values where no actual work exists - in the future - rather than the S-Curve flatlining after the last reporting period.
> iif([actual work]=0,NULL,sum(periodstodate([time].[(all)]),[measures].[actual work]))

Capacity Heatmap (Remaining capacity percentage)
A nice simple one for Excel Services conditional formatting, calculating the % of capacity that is remaining based on the Work values.
> ([Capacity]-[work])/[capacity]

Filtering a measure based on a dimension member to derive custom cube measures

imagine the scenario.  On your report you want to put the following onto a stacked column chart
- Actual Work spent on Project Priority 1 projects
- Actual Work spent on Project Priority 2-4
- Resource Capacity (as a line)

note:  Your priority field is a flat Lookup Table that doesnt have this "P2-4" grouping built in

In this scenario to easily derive these values:
1 - Create a measure for Actual Work spent on P1 projects: 
ActWorkP1                   ([measures].[actual work],[Project Priority_Project].[Priority 1])
2 - Create a measure for Actual Work spent on "everything else" besides P1 Projects
ActWorkP2-4                [Actual Work]-[ActWorkP1]

This may seem like an edge case and you can of course use a pivot table to cross analyse and filter for these values, but what this DOES give you is an interesting OLAP based source for KPI's....

Next target:  I am currently looking at how I can derive a custom measure of the actual work done on one "Administrative" task across any given timesheet period....

More to follow!


Popular posts from this blog

#projectserver2013 VIEW FAILURE: The view failed to load. Press OK to reload this view with the default settings. Press cancel to select another view.

** UPDATE ** includes notes relating to secondary bug where Timesheet is created without Administrative tasks.

Does this ring any bells?

This has been bugging me for months, but finally I have a repro for this:

Issue Summary:  When a task is deleted from a plan that is approved into a previous or current timesheet - even when there are no actuals on the task - you can no longer view the timesheet

The following repro has been proven:
- Setup system with Single Entry Mode, with enforced Status Approval before Timesheet Approval
- Create resource as own timesheet manager
- Create new project
- Create two tasks in the same week, starting monday with 5 days duration:  1) Task to assign actuals, 2) Task to delete post submission
- Assign Resource to tasks
- publish project
- as Timesheet User, go to the appropriate timesheet period for the tasks created
- Assign actual work to one task (task 1), leaving task 2 with no actual work
- Submit timesheet
- as Project Status Manager, approve the time on task 1 …

What to do when your application server goes bang

What happens when someone kills your Application Server?
So imagine the scenario:
Three Server Solution - SQL - SharePoint 2010 and Project Server 2010 Application Server (Central Admin Host) - Wfe/ReportServer
We wake one bleary Monday morning to find that some numpty has killed the application server and the users are baying for blood.
Well surprisingly SharePoint handles this disaster recovery scenario particularly well.  Well.  Better than I thought it would to be honest.
Rough steps:
- quick SQL backup to be safe - Rebuild your application server - reinstall pre-reqs - reinstall SP, PS, SPFSP1, SPS+PSSP1, Cumulative Update and other stuff you usually put on there. - Run your configuration wizard to reattach to the Farm, and select Host CA Site
The last step was what I was VERY wary of.  Would the server simply reattach to the Farm, even when there is no CA server available?  
Bingo your back.... almost.... you are going to get errors a-gogo in your event log as things just aren't quite back…

Reporting from Project Server 2016 - multiple sites and userviews

Just a quickie...
I've been interested in how MS have handled the "multiple PWA sites in a Content DB" thing since I read that this was their new approach.  Most of my reporting is via SSRS so i am reliant (still... in 2016) on DB queries rather than OData feeds (tsk) and this "querying a PWA DB with more than one PWA site in it is unsupported" quote was worrying me.

So it looks like what is happening is this.

When you create the first PWA site in a Content DB it hard-codes the SiteID into the _Userview view design elements.  This means that your first PWA Site is the default.  All the data for subsequent sites are still held in the tables against separate SiteID's but you cannot utilise the OOTB _Userview components (see below)

SELECT        ProjectFields....
FROM            pjrep.MSP_TVF_EpmProject('FF19B767-CA6D-4C4C-B123-C0B5AE5354D6') AS MSP_EpmProject