Want to know The Truth About CPM?

06 March 2013

Stupid Planning query #12 -- Calculation Manager Rights

Introduction

Arrrgh, this one really got me going. Actually, I have noticed that I have never written a query against the Planning tables unless I am unable to get whatever it is out of Planning easily. And I suppose that sort of makes sense. And I also that means I am always annoyed and that missing Planning reporting features are my opportunity to increase my SQL skills, such as they are. Of course writing the query took way longer than I thought it would. Read on for the reason...

With that preamble, have you ever wondered what security is assigned to Calc Mgr rules in Planning? You basically have to go into each rule and edit the security to see what user or group has been assigned and what rights are set. Annoying, isn't it? And not practical when there are many rules. Here's an example of what it looks like:

I can see that the group PLN_CalcTest_Consol has Launch access to the rule AggAll, but what about AggPlan, CalcRev, etc., etc., etc.?

So yes, this is yet another opportunity to query the tables. And oh yes, I am using this as a teeny part of the Planning presentation I am giving with Jessica Cordova (hi, Jessica) at Kscope13.

NB – One other note, I was inspired to get around to this query in response to “vaio” and his Hyperion Business Rules security query from this Network54 thread: http://www.network54.com/Forum/58296/thread/1362011042/Export+only+Webform+security I figured if world+dog had it for EAS’ business rules, we needed it for Calc Mgr as CM is all there is from 11.1.2.2 onwards.

The reason this query drove me up the wall

Would you believe that deployed Calculation Manager rules do NOT have an object type in Planning? Would you believe that I spent more than a little bit of time trying to find it?

Oh yes, both statements are true. The latter one you are going to have to take on trust. The former I can prove.

Here are the Object Types in the Planning app schema:
SELECT DISTINCT
OT.OBJECT_TYPE,
OT.TYPE_NAME
FROM
HSP_OBJECT_TYPE OT
OBJECT_TYPETYPE_NAME
1
Folder
2
Dimension
3
Attribute Dimension
4
Calendar
5
User
6
Group
7
Form
8
FX Table
9
Currency
10
Alias
11
Cube
12
Planning Unit
30
Attribute Member
31
Scenario
32
Account
33
Entity
34
Time Period
35
Version
37
Currency Member
38
Year
45
Shared Member
50
User Defined Dimension Member


And here is the OBJECT_TYPE that goes with Calc Mgr rules:
SELECT
*
FROM HSP_OBJECT
WHERE
OBJECT_TYPE = '115'

See the 115? I only know that because I did a search on the name of one of the rules and thus figured it out.

Why would you care about OBJECT_TYPE 115?

Well, once you (or I) knew this, you (or I) could write this:
/*
Purpose: Calculation Manager security report by rule, group, and user
Modified: 1 Feb 2013
Notes: Common Table Expressions make joining mostly disparate objects
relatively easy.
NB -- Calc Mgr rules do NOT have an OBJECT_TYPE in HSP_OBJECT.
The OBJECT_TYPE seems to be 115.
*/
-- I am in love with CTEs over subqueries
WITH
-- CTE for Calc Mgr OBJECT_ID, Plan Type, and Name
BRName (CMID,PlanType, BRName) AS
(
SELECT
CMR.ID,
CMR.LOCATION_SUB_TYPE,
O.OBJECT_NAME
FROM
HSP_CALC_MGR_RULES CMR
INNER JOIN
HSP_OBJECT O ON O.OBJECT_ID = CMR.ID
),
-- CTE for Calc Mgr user OBJECT_ID, Calc Mgr OBJECT_ID, and Launch rights
BRAccess (UserID, CMID, Launch) AS
(
SELECT
AC.USER_ID AS 'User ID',
O.OBJECT_ID AS 'CM Obj ID',
--O.OBJECT_NAME 'CM Name',
CASE AC.ACCESS_MODE
WHEN -1 THEN 'No Launch'
WHEN 4 THEN 'Launch'
ELSE 'Unknown'
END AS 'Access'
FROM
HSP_ACCESS_CONTROL AC
INNER JOIN
HSP_OBJECT O ON O.OBJECT_ID = AC.OBJECT_ID
WHERE
O.OBJECT_TYPE = '115'
),
-- CTE for user OBJECT_ID, user name, group name
UsersInGroups (UserID, [User Name], [Group Name]) AS
(
SELECT
--O.OBJECT_ID AS 'User ID',
O2.OBJECT_ID AS 'CM Obj ID',
O.OBJECT_NAME AS 'User Name',
O2.OBJECT_NAME AS 'Group Name'
FROM
HSP_USERS U
INNER JOIN
HSP_OBJECT O ON O.OBJECT_ID = U.USER_ID
INNER JOIN
HSP_USERSINGROUP UG ON UG.USER_ID = U.USER_ID
INNER JOIN
HSP_OBJECT O2 ON O2.OBJECT_ID = UG.GROUP_ID
)
SELECT
BRN.BRName AS 'Calc Mgr rule',
BRN.PlanType AS 'Plan Type',
BRA.Launch AS'Launch',
UIG.[User Name] AS 'User name' ,
UIG.[Group Name] AS 'Group name'
FROM
BRAccess BRA
INNER JOIN
UsersInGroups UIG ON UIG.UserID = BRA.UserID
INNER JOIN
BRName BRN ON BRN.CMID = BRA.CMID
ORDER BY BRN.BRName, UIG.[Group Name], UIG.[User Name]

And then you (or I) could run the above query, and get the following:
Calc Mgr rulePlan TypeLaunchUser nameGroup name
AggAllConsolLaunchTestPlanner1PLN_CalcTest_Consol
AggAllConsolLaunchTestPlanner2PLN_CalcTest_Consol
AggAllConsolLaunchTestPlanner3PLN_CalcTest_Consol
AggPlanConsolLaunchTestPlanner1PLN_CalcTest_Consol
AggPlanConsolLaunchTestPlanner2PLN_CalcTest_Consol
AggPlanConsolLaunchTestPlanner3PLN_CalcTest_Consol
CalcRevConsolLaunchTestPlanner1PLN_CalcTest_Consol
CalcRevConsolLaunchTestPlanner2PLN_CalcTest_Consol
CalcRevConsolLaunchTestPlanner3PLN_CalcTest_Consol
ClrBSConsolLaunchTestPlanner1PLN_CalcTest_Consol
ClrBSConsolLaunchTestPlanner2PLN_CalcTest_Consol
ClrBSConsolLaunchTestPlanner3PLN_CalcTest_Consol
ClrFinalConsolLaunchTestPlanner1PLN_CalcTest_Consol
ClrFinalConsolLaunchTestPlanner2PLN_CalcTest_Consol
ClrFinalConsolLaunchTestPlanner3PLN_CalcTest_Consol
ClrTrgtsConsolNo LaunchTestPlanner1PLN_CalcTest_Consol
ClrTrgtsConsolNo LaunchTestPlanner2PLN_CalcTest_Consol
ClrTrgtsConsolNo LaunchTestPlanner3PLN_CalcTest_Consol


Isn't that pretty? And useful? I (or you) think so.

The sting in the tail

Would you believe I spent a good half hour poking around in the Calculation Manager tables?

Would you believe that the CALCMGROBJECTACCESS table in the Calc Manager schema is completely empty? I have no idea what it is for, but it isn't for rules deployed to Planning. Terrific.

But the good news is that with a little poking about writing a simple (well, CTEs aren’t totally beginner’s stuff but they are so easy to read and work with) query, you (or I) can easily look at who and what kind of access planners and groups have to deployed CM business rules.

Be seeing you.

23 February 2013

Stupid Planning queries #11 -- Where and what are my Smart Lists

Where oh where has my Smart List gone?

Smart Lists are a wonderful thing. Well, that may be slightly exaggerating their usefulness but if you want to create a drop down list in a Planning Account (or other dimension but I have never seen it) Smart Lists are the way to go. Come to think of it, they are a bit of a Hobson’s Choice (a truly fantastic movie) if you want dropdown lists in Planning forms.

Planning even gives you a great way to view the Smart Lists in your Planning application by simply going to the Administration->Manage->Smart Lists menu.

Here is a (rather short) list of Smart Lists in my sample Planning app:

Live and in person
This is a very silly and pointless form that nevertheless shows a Smart List with nothing selected.

Clicking on the down arrow:

Selected Yes


Saved to Essbase


FWIW, if I pulled the Account YesOrNo in Essbase using a Smart View adhoc analysis link, I would get a 1 in that cell as, bizarrely, Smart Lists do not resolve to Essbase Text Measures. I will try not to think about why that is the case as their functionality is the same. Different development groups is the best explanation I can think of but it is frustrating. Onwards, regardless.

So all of this is great, and more than a little basic
Yes, I know, what is there to query if you just created the Smart List? Well, in the case of this sample Planning application, there is no real reason to query much of anything as we know what the Smart List is and what member it’s tied to.

But what if you didn’t know what member the Smart List was assigned to? How would you know? As far as I can tell, there is no magic report in Planning that will give out this information.

A different story
And what if you were working on a Planning migration/modify project (ahem) and the Planning application had 31 Smart Lists, and somehow the association of Smart List to member got lost (oh, thank you accursed EPMA), and you had to go back to the original Planning app to figure out what goes where? What would you do then? Scream? Cry? Curse your bad luck? Or how about write a query that looks just like this?

The query

/*
    Purpose:     Figure out what Smart Lists are assigned to which Members
    Modified:    23 February 2013, Cameron Lackpour
    Notes:       This is a nice and easy one, isn't it?
*/
SELECT
  O.OBJECT_NAME AS 'Member',
  E.ENUMERATION_ID AS 'SL #',
  E.NAME AS 'Smart List'
FROM
  HSP_MEMBER M
INNER JOIN
  HSP_ENUMERATION E ON M.ENUMERATION_ID = E.ENUMERATION_ID
INNER JOIN
  HSP_OBJECT O ON O.OBJECT_ID = M.MEMBER_ID


And that produces a result set like this:


That hypothetical Planning application I mentioned above? Would you believe 31 Smart Lists of which 14 were actually assigned? Yup, 17 dead Smart Lists. Isn’t application maintenance a stinker? Apparently so.

Everything you ever wanted to know about a Smart List
Above I joined HSP_ENUMERATION (why wasn’t the tabled called HSP_SMARTLIST?) to HSP_MEMBER to get the link between member (in any dimension) and Smart List. But what if you just wanted a quick review of everything that ever made up a Smart List?

Query the second

/*
    Purpose:     Smart List contents by name
    Modified:    23 February 2013, Cameron Lackpour
    Notes:       Another Nice 'N Easy one.
*/
SELECT
      E.NAME,
      EE.ENTRY_ID,
      EE.NAME,
      EE.LABEL
FROM
      HSP_ENUMERATION_ENTRY EE
INNER JOIN
      HSP_ENUMERATION E ON EE.ENUMERATION_ID = E.ENUMERATION_ID
And that produces a result set like this:


And that’s it
I have to say that I wrote this blog post because I needed to get that list of Smart List associations to members and simply couldn’t find it on the series of tubes that make up the world wide web.   I’m sure it exists, somewhere, or maybe it was just so easy no one bothered to post it. Regardless, now world+dog has it.

I will note again what an incredbily helpful thing it is to write these queries – I cannot imagine going through each one of the Accounts in the application I am talking about (over three thousand across multiple Plan Types) and try to find the silly things – I’d have completely gone off my rocker (although I will admit it might be hard to spot when that happens) and I would have spent a *long* time trying to figure out where the non-assigned 17 Smart Lists should have been. Which was nowhere, thanks to the query. SQL saves the day yet again.

Be seeing you.