56
Data Level Security in Cubes Using ParameterMaps Data Level Security in Cubes Using Parameter Maps In this article I will look at a real-world example of data level security filtering. Cognos does provide some role based security filtering capability. I think the problem with roles is that there is usually an attribute associated with the role... and that on the other hand is not supported out-of-the-box. Consider the following example, to undertsand what I mean by "attribute associated with the role" Suppose we have the usual GO-Sales kind of data. We have a Sales measure and one of our dimensions is Branch. We have two roles: CEO and Branch_Manager Our requirement is that CEO can see everything but a Branch_Manager can only see Sales by his or her own branch. This is the point where role-based security goes week. Somehow we need to store which Branch a Branch_Manager is allowed to see. It's not sufficient to know that a user has Branch_Manager role... we need to know (and handle) a BranchID associated with that role. This is what I call the "attribute associated with the role" - in our example the BranchID. Usually this implies we need to store this somewhere, eg in the database or maybe in a directory server like LDAP. To implement data level security I find the best option is to use Slicers all over the place where cubes are referenced - in queries used by crosstabs and charts on the reports, in queries used to populate prompts on the filter pages. (Keep in mind, I firmly believe that lists should not be

Cognos Tips

Embed Size (px)

DESCRIPTION

This Tips is usefull for Cognos Developers

Citation preview

Page 1: Cognos Tips

Data Level Security in Cubes Using ParameterMaps Data Level Security in Cubes Using Parameter Maps

In this article I will look at a real-world example of data level security filtering.

Cognos does provide some role based security filtering capability.I think the problem with roles is that there is usually an attribute associated with the role... and that on the other hand is not supported out-of-the-box.

Consider the following example, to undertsand what I mean by "attribute associated with the role"

Suppose we have the usual GO-Sales kind of data. We have a Sales measure and one of our dimensions is Branch.We have two roles: CEO and Branch_ManagerOur requirement is that CEO can see everything but a Branch_Manager can only see Sales by his or her own branch.

This is the point where role-based security goes week.

Somehow we need to store which Branch a Branch_Manager is allowed to see.It's not sufficient to know that a user has Branch_Manager role... we need to know (and handle) a BranchID associated with that role.This is what I call the "attribute associated with the role" - in our example the BranchID.

Usually this implies we need to store this somewhere, eg in the database or maybe in a directory server like LDAP.

To implement data level security I find the best option is to use Slicers all over the place where cubes are referenced - in queries used by crosstabs and charts on the reports, in queries used to populate prompts on the filter pages.(Keep in mind, I firmly believe that lists should not be used with a dimensional datasource.)The slicer will make sure that filtering is applied to the entire cube, regardless of the dimensions used for display.

To continue with the example we need to write a slicer that figure out who the current user is what role the current user has - is the user a Branch_Manager what attribute is associated with that role - value of the

BranchID

Page 2: Cognos Tips

So what tools are in or arsenal to tackle this?

Session Parameters

Session parameters provide a way to get an identifier of the current user.

e.g. account.userInfo

Tamas Simon

Session parameters can be used in macro expressions. The syntax is to prefix them with a ``$'' (dollar sign)

e.g.#sq($account.userInfo)#will result in'Tamas Simon'

The exact details depend on how Cognos is configured...Bottom line is that in every Cognos installation there should be some sort of identifier of the current user and it's accessible to report expressions using session parameters.

You can check the session parameters in Framework Manager by selecting Project / Session Parameters... from the menu.

Parameter Maps

Parameter maps are similar to session parameters in that they can be accessed from macro expressions.They are name-value pairs, or rather "key-value" pairs - as Cognos calls it.They are defined in the Framework Model.They can be based on a query, just select a column for Key and another for Value.

Syntax is similar to session parameters.``$'' (dollar sign) infornt of the name``{}'' (curly braces) surrounding the key``''' (single quote) surrounding the key if it is a string literal

Page 3: Cognos Tips

e.g.#$pmUserAccessableBranches{'Tamas Simon'}#

Here are some important notes I'd like to make:

1., There is no way to include or exclude parameter maps from a package. In my understanding when you re-publish a pckage all parameter maps are published with it.

2., The query subject that the parameter map is based on has to be published in the package. Otherwise you won't get any error or warning messages but the parameter map will be empty, always returning its default value if you have defined any.I remember reading that the query is executed everytime an expression references the parameter map - but I have not confirmed this.

string aggregate function

3., Keys are unique. This is tricky... to continue our example imagine that we want to be able to assign multiple branches to the same user.In other words we want to control which branches a user is allowed to access (maybe only one, maybe more)So in the parameter map we need to have a list of IDs associated with a Key, all within a single string (stored as the Value)

e.g.

database tableUserName BranchID

Tamas Simon B1

Tamas Simon B2

Tamas Simon B3

we would want the parameter map to look like

pmUserAccessableBranchesKey Value

Tamas Simon B1 B2 B3

This is tricky considering that we need to write a query to populate the parameter map... but it's doable.Oracle for example does not provide a string aggregate function out-of-the-box but one can write his own.

Page 4: Cognos Tips

select  UserName as Key,  stragg(BranchID) as Value from UserAccessableBranches group by  UserNameYou can find a string aggregate function e.g. here: http://www.oracle-base.com/articles/10g/StringAggregationTechniques.php#user_defined_aggregate_function

With these three tools: session parameters, parameter maps based on DB query and string aggregation we can solve our data level filtering challenge.

We end up with slicers something like this:filter(  [Branches Dimension].[Branch], roleValue('_businessKey', [Branches Dimension].[Branch])  in (   #csv(split(' ', $pmUserAccessableBranches{$account.userInfo}))#  ) )from the inside out:get the current user via session parameter: $account.userInfouse this as a Key to look up the user accessable branches from the parameter map: $pmUserAccessableBranches{$account.userInfo}massage the macro until it returns a comma separated string: #csv(split(' ', $pmUserAccessableBranches{$account.userInfo}))#use the whole thing to filter branches... resulting in a slicer member set.

We could just generate a set() expression using the prompt...

set( #join(',', substitute('^', '[Branches Dimension].[Branch]->:[PC].[@MEMBER].[', substitute('$', ']', split(' ', $pmUserAccessableBranches{$account.userInfo}))))# )

This would work if the IDs are in synch with the cube. Otherwise we might get an error from Cognos, saying basically that we are refering to a member that does not exist. I find it safer to use the filtering expression. Posted by Tamas Simon (Sic) at 8:36 PM 4 comments

Tuesday, November 11, 2008How to use the "Range Prompt" - some undocumented features The TextField prompt has an interesting feature: it can be used to get two values instead of one by setting its ``Range'' property to YES.

This is handy when you want to filter by a range

Page 5: Cognos Tips

that has a lower and/or an upper value.

The extra that the prompt gives you is that you can have open intervals ie. cases where the user only specifies and upper or a lower value.

e.g. filter lines where some ratio is less than 80% beteen 60% and 80% greater than 80%

It saves you from having to do some sort of javascript voodoo with radio buttons etc.

The trick is that you want to set the prompt as optional (= not required) because otherwise it would be just two textfields, which is not any better than using two textfield from the first place.

Now... since the prompt is optional the user does not have to input values.If the user leaves both the lower and the upper values unspecified... the prompt does not return anything.And this is a problem......because you are trying to use the prompt in an expression using the in_range operator that looks something like this

filter(my_dimension, my_measure in_range ?pRange?)

and this blows up!After the prompt is evalued it becomes the following expression:

filter(my_dimension, my_measure in_range )

...that's right, the prompt did not return absolutely anything

To fix this you need to use the long form of the prompt macro and set the datatype to ``range''.This is undocumented as of 8.3 ... but it works

to fix the expression specify a default range that the prompt should return when the user left both lower and upper values unspecified. e.g. can be an open range starting with 0

filter(my_dimension, my_measure in_range #prompt('pRange', 'range', '{0:}')#)

Page 6: Cognos Tips

Posted by Tamas Simon (Sic) at 7:27 PM 0 comments Links to this post

Thursday, September 4, 2008[updated] Relative Package Names It is possible to have a report be built on a package that is specified with a relative (to the report) location.It is not possible to set relative package names through the UI in ReportStudio but you can copy the XML source into an editor, make the changes and paste it back to RS.The reference to the package is right at the beginning of the XML in the <modelPath> tag.I tested with relative path on 8.3 and it worked.

This is great for keeping multiple environments on the same Cognos box.The report age can be the same. There is no need to relink the report with a different package. The package can be redeployed into different folders (new feature in 8.3) with the same name. The packages would be practically the same only they would use different datasources. Changing the datasource is easy... just run a sed script on the model's XML and publish.If you need to maintain a lot of environments eg. QA, staging, production, support on the same Cognos then you will find this very useful!

UpdateDamn, it doesn't work. Report Studio axccepts the relative path but before saving the report it substitutes it with an absolute path.the good news is that in 8.3 you can relink a report to another package through the portal by setting the properties... there's no need to open up the report in RS. Posted by Tamas Simon (Sic) at 10:55 PM 1 comments Links to this post Labels: deployment, package, relink, report

Monday, September 1, 2008Crosstabs with Column Headers aka How to make Crosstabs that look like lists

| sales------+--------------+---------branch| sales person | <1234> +--------------+--------- | sales person | <1234>

will look like

Page 7: Cognos Tips

| sales -----------+---------+--------1st Avenue | Aaron A | 1,000 +---------+-------- | Betty B | 2,000-----------+---------+--------2nd Street | Clare C | 1,500 ...

If it was a list it would have column headers and would look like this:

branch | sales person | sales -----------+--------------+--------1st Avenue | Aaron A | 1,000 +--------------+-------- | Betty B | 2,000-----------+--------------+--------2nd Street | Clare C | 1,500 ...

To achieve this using a crosstab you need to add extra Text Items and hide some cells by setting their box type to ``none''

HIDE | "branch" | "sales person" | sales---------------------+----------+----------------+------branch| sales person | HIDE | HIDE | <1234> +--------------+----------+----------------+------- | sales person | HIDE | HIDE | <1234>

Hiding the top left corner will pull the extra Text Items to the left so that the "headers" will nicely align with their columns.But adding these new text item still creates extra empty columns in the crosstab... these have to be hidden as well.

The resulting crosstab will look just like a list, displaying column headers.

You may need to play around with styling it to get everything in the right color.... Posted by Tamas Simon (Sic) at 12:02 AM 4 comments Links to this post Labels: column header, crosstab, list

Page 8: Cognos Tips

Thursday, July 31, 2008Difference in dimensional expressions between RS8.2 and 8.3 - part two I found another one

code in 8.2

set( emptySet([My Dimension].[My Hierarchy]) )

code in 8.3

set( item(emptySet([My Dimension].[My Hierarchy]),0) )

without the use of item() you get an errorInvalid coercion from 'memberSet' to 'member, measure'even though the expression validates.

This is important when you want to create prompts that return MUNs but are optional.As a recap from my older posts optional for a prompt means that it has a default value. The default is ... no members selected...in other words: empty set Posted by Tamas Simon (Sic) at 2:07 PM 2 comments Links to this post Labels: 8.3, emptySet, set

Tuesday, July 29, 2008Difference in dimensional expressions between RS8.2 and 8.3 We are just upgrading to Cognos 8.3 (I know, I know...) and I've just found this difference in the use of the filter() function:

I think it actually makes more sense in 8.3... probably that's why they fixed it.

Code in 8.2

filter([My Dimension].[My Hierarchy].[My Level],roleValue('_businessKey', currentMember([My Dimension].[My Hierarchy])) contains ?Param1?)

Code in 8.3

Page 9: Cognos Tips

filter([My Dimension].[My Hierarchy].[My Level],roleValue('_businessKey', [My Dimension].[My Hierarchy].[My Level]) contains ?Param1?)

In 8.2 one had to use the currentMember() function to refer to the member being filtered.In 8.3 it is not needed. Instead one can just use the level. Posted by Tamas Simon (Sic) at 11:38 AM 0 comments Links to this post Labels: 8.3, currentMember, filter

Tuesday, June 24, 2008Version 2 is Coming ;-) My second baby is about to be born this week.You won't see much blogging for the next couple of weeks.When I come back I'll write about our experiences switching the DMR model to OLAP.We're evaluating both Cognos PowerPlay and MS Analysis Services... Posted by Tamas Simon (Sic) at 7:07 AM 1 comments Links to this post

Monday, June 23, 2008See generated MDX when using DMR model When you use a DMR model you'd expect that Cognos Report Studio generates MDx expressions, since the framework model is supposed to look just like any other cube from a report author's perspective.Yet, when you click on a query and select "Geenrated SQL/MDX" from the properties you can only see Native and Cognos SQL.I've recently learned that there is a way to see MDX...Click "Tools"/"Show Generated SQL/MDX" and you'll have the option to see Native MDX.Why you cannot see the same when you go from the properties... ask Cognos.

Another interesting thing is that the generated MDx ends with something like this:FROM [F:/Cognos8.2\./bin\../temp\dmbTemp_5324_0004_12142423860.dmc]

Looks like the generated SQL will result in a query that gets fetched into a temporary cache (or cube???) that can then process MDX expressions.

ps I tried this on 8.2, I wonder if there are any changes in 8.3 Posted by Tamas Simon (Sic) at 10:29 AM 0 comments Links to this post

Tuesday, June 3, 2008

Page 10: Cognos Tips

Advanced TreePrompt I have played around with Treeprompts lately and would like to show you tow different usage of this handy tool.

Treeprompt provides a hierarchical selection tool.you just point it to the top of the hierarchy tree that you want to select from and it lets the user make selections at any level.

Page 11: Cognos Tips

Actually you don't have much control over it, it goes down to the leaf nodes (lowest granularity) whether you want it or not.

e.g. there is no way to "stop" this treeprompt aty the product line level...it will always allow the selection of products.

I find Treeprompts very useful in two scenarios:

As a replacement for a list of subsequent combo boxes (having "cascading" master-detail relationships.

Page 12: Cognos Tips

This provides the user with fine grained selection in an easy way.

The treeprompt return the member selected, so in this case we want to automagically "expand" that member if it's at a higher level to include all lowest level members.

e.g.

user makes a selection at the product item level but we still want to display all "selected" products.

Selection: Cooking Gear, Rope

Page 13: Cognos Tips

We can see what the prompt return by dropping a Text Item, setting it's Source Type to "Report Expression" and setting the Expression to ParamValue('pProduct')Where pProduct is how I named the prompt's parameter.

This will return:[Sales].[Product].[Product].[Product type]->[all].[1].[1], [Sales].[Product].[Product].[Product type]->[all].[2].[6]

In a crosstab, summary kind of report we want to see all products that the user selected:

in the crosstab's query we need to get the descendants of every member returned by the prompt at the product level:

Page 14: Cognos Tips

union( descendants( set( # join(',', split(';', promptmany('pProduct', 'MUN')) )# ), [Sales].[Product].[Product].[Product]) , emptySet([Sales].[Product].[Product]) )

Charts

If we are dealing with charts treeprompts are also very handy because we can allow the user to have full control over how many series to display in the chart.

In this case we do not want to "expand" the selection.

The expression to use here is more simple:

set( #promptmany('pProduct', 'MUN')#) Posted by Tamas Simon (Sic) at 2:30 PM 1 comments Links to this post

Monday, May 26, 2008

Page 15: Cognos Tips

Design Utility I had this idea to create a utility that can be used during the dimensional design process.

The design starts off from looking at the requirements.

1. What are the reports? This is usually well known...

2. What metrics are there?This is sometimes lesser known as the business analyst may not recognize that different metrics are really the same, just rolled-up differently.e.g. He/She may have a "sales total metric" and a "branch sale for the month" metric.I suggest using two terms to differentiate here e.g. in the requirements document call it metric, in the design document call it measure. "measure" can then become sort of the "normalized metric.

Start the design by collecting these, why not enter this information into two tables: Report and Metric

3. Collect the different levels where the metrics appear.4. Figure out which levels belong to the same dimension. 5. What are the attributes that have to be displayed for each level? 6. Categorize the levels into hierarchies. Is there a need for more

than one hierarchy per dimension?

Store all this into table also. So far we added Level, Attribute, Dimension and Hierarchy, HierarchyLevel

7. Which metric appears at which level? What is the roll-up aggregation?

8. Which report uses which metric at which level?

Yes... store this info also in tables. Add MetricLevel, ReportMetricLevel

9. ... and there you go!

You can use a simple Ms Access or OpenOffice Base database to store all this information.Then you can create very interesting reports from this:

1. Dimension hierarchyReport on the Dimension, Hierarchy, Level and Attribute tablesWill describe what dimensions to create and how to set them up

2. Cube designReport on the MetricLevel, Level, Hierarchy, Dimension tables

Page 16: Cognos Tips

Will describe what cubes to create, what are the roll-up aggregations

3. Report usage of metricsReport on the ReportMetricLevel, MetricLevel, Level, Metric, Report tablesWill describe how the requirements are met and how each report will be built from the dimensional model

4. Star Schema designReport on the Metric, MetricLevel, Level, HierarchyLevel tables. Find the lowest granularity level in each hierarchyWill describe the star schema structure

A utility like this can be written in about a day or two in MsAccess.It helps to verify the requirements and produces all sections (of what I can think of) of a "design document".

It can be reviewed and has sufficient information to start implementation.

Furthermore I would suggest to create a placeholder model i.e. one with no real values for measures, but all dimensions hooked up.The bulk of the work goes into building the "real" metrics.

The placeholder model serves a double purpose: Development can be split between report authors and modelers,

here modeling really means implementing the logic for each metric.

A mock-up of each report can be created that in my opinion shoud still belong to the design phase. This can be reviewed with the customer and serves to verify both the design and the requirements.

If you are interested in this utility please let me know... Posted by Tamas Simon (Sic) at 11:42 PM 1 comments Links to this post Labels: design, utility

Wednesday, May 21, 2008Cognos jobs are fragile While working with cognos jobs to automate testing I found that jobs are sometimes not very well suited to do this.

The issue is that it's very easy to break them while working on the reports.

Certain types of updates to the report invalidates the job, e.g. if you rename a report or even if you use copy-paste through the clipboard.

Page 17: Cognos Tips

Another problem is if there are any changes to the prompt pages or the parameter values. Since these are stored in the job it won't be able to fill out the prompt pages properly when it's trying to run the reports.

Conclusion

Since I don't know any better I still think it's a good idea to use jobs to automate unit and smoke testing. It's just that we have to keep an eye on them to make sure they're not broken. Posted by Tamas Simon (Sic) at 11:28 PM 0 comments Links to this post Labels: automated test, job, smoke test

Tuesday, May 6, 2008Automating Test I'd like to briefly share some approaches I came up with that fit in the bigger picture of "software lifecycle" on Cognos, namely how we can do a sort of automated regression testing, or smoke testing.

What should be tested

I would suggest testing all layers individually, not just the final reports, and always just test the extra functionality that the layer provides.

In case of dimensional modeling the three layers to test are star schema dimensional model reports

Depending on whether you use DMR or "real" OLAP the star schema and the dimensional model may or may not be implemented using Cognos.Doesn't really matter... it still needs to be tested.

How to test 

Testing the star schema is best done outside Cognos. There are two things to verify: First, the structure, that you really get as many rows (and columns) as you think you get.The star schema contains the lowest granularity of each measure so there should be one and only one record for each combination of the dimension members.

Page 18: Cognos Tips

And I would argue that there should be a record for every combination even if there was "no data". (One of the great inventions of extra early mathematicians was the number zero. Use it!)Second, verify the numbers. Especially with complicated metrics.

To test the dimensional model you can create simple "unit test reports".The purpose here is to verify that the dimensions are set up properly and associated properly with the measures - especially if this is a DMR model - and that the roll-ups are working properly.A "unit test report" can contain one or more crosstabs where the measure (or group of measures) is displayed along two dimensions.If you have more than two dimensions then you may want to create a giant crosstab with nested dimensions or multiple smaller ones.

To test the final reports... well just run them. It may be useful to create a checklist that you use to double check each small little thing. this would have items like "Page Number appears in footer", "title is all caps and centered" etc.

How much of this can be automated

Cognos has a feature called "jobs" that becomes very useful for testing.Jobs basically let you preset the report parameters - by actually presenting the prompt pages but not running the report and then runs the report either right away or later at a scheduled time.

You can create the above mentioned "unit test reports" and add them all to a job.

You can also add all your reports fill out the prompt pages and use this job for smoke testing.If a report cannot be run the job will show that the execution failed.

If you need to run the same report several times with different parameter settings then use what Cognos calls the "report view"... it lets you do exactly this.

The outputs of the reports can be saved. I suggest saving as XHTML or XML.

Regression testing

Page 19: Cognos Tips

You don't have to go over each report result by hand. (or at least not every time)You can save a reference version of each report result on your local file system and then use this to compare the results of the unit test or smoke test jobs.You can write a simple script that downloads the latest report results (e.g. using wget) and compares it  (e.g. diffxml or Altova XML tools) with the reference version. This takes a couple hours to write but it's well worth it.Cognos support a URL that looks something like this:folder[name=...=]/defaultOutput(report[name=...])What I'm trying to emphasize is the defaultOutput() so your script does not have to know the most recent version number or date of each report result.

The benefits once again:smoke test job - allows one-click smoke testunit test job plus script - allows regression testing (aka JUnit)

One last thing

Of course at least once you need to verify that your "reference version" of each report is correct. There is no way to automate that.In my opinion the best approach is to construct some well know test data.Depending on the business the logic behind each measure can get quite complicated and the ETL part - massaging the transactional data set until you get the measure values in the star schema - can become very very tricky.

I often here from tester that they want to see a query to verify that the numbers in the star schema are correct.I think it's not a good approach. After all I was happy to create one query... now should I create a second one to verify the first one?It's much easier and more solid approach to work with data where the expected values are well known. Then there is no need for queries to get the value of a measure.e.g. if there were 2 sales a day in January and 4 sales a day in February then testing the Daily Average Number of Sales measure becomes easy...

I hope I gave you some ideas in regards to testing a Cognos solution...Posted by Tamas Simon (Sic) at 10:37 PM 0 comments Links to this post Labels: automated test, smoke test, test, unit test

Friday, April 25, 2008

Page 20: Cognos Tips

when to use completeTuple() I found a case when you need to use completeTuple even though tuple() - to me at least - would seem like a reasonable choice too.This is when you have dimensions in context that do not apply.

an example will help

Let's say you have branches who make sales and you set a sales target, however this target is the same for all branches. You set a different target for every month.

Yo want to have a crosstab report showing the sales of each branch for every month and the sales target also:

SalesMonth

  Sales TargetSales

Branch   

The thing is that if you don't use completeTuple() in the expression to get the Sales Target then Cognos will get "confused" by the presence of "Branch" which is not in scope for the Sales Target measure.

You need to write something like this:

Sales Target:=completeTuple([Sales Target], currentValue([Time Dimension].[YMD hieararchy]))

...especially if your crosstab is more comlex than this example...

Posted by Tamas Simon (Sic) at 1:15 AM 0 comments Links to this post

Tuesday, April 22, 2008why Filters Should Be Avoided When Working with a Dimensional Model I can see three scenarios when you may think that you need to use a filter:

Page 21: Cognos Tips

Filtering along the axes of a crosstab

Say you have a typical crosstab with one dimension along the horizontal axes and another one along the vertical axes. e.g.

<Sales Total> <Date> <Date>

<Product Type> <1234> <1234>

<Product Type> <1234> <1234>

which would give you something like:

Sales Total 1/1/2007 ... 04/21/2008 04/22/2008

Camping Equipment

1,000$ ... 1,000$ 1,000$

... ... ... ... ...

You want to filter the time dimension you only report for the year 2008. Or you want to only include product types with "camping" in the name. What you really want in this case is to build a memberset that you will then use as the axes of the crosstab. When you drag-and-drop a dimension level in Report Studio it really translates to something like members([my_Dimension].[my_Hierarchy].[my_Level])e.g.members([Product Dimension].[Product Type Hierarchy].[Product Type]) (Check "Corercion Rules" in the Report Studio documentation.)

Instead of getting all members you need to build a member set. You can do this by putting members together... or taking members away from the full set.

The former could be done with techniques such as[my_Dimension].[my_Level]->?Parameter1?e.g.ancestors([Time Dimension].[YMD Hierarchy].[Year]->?Year?, [Time Dimension].[YMD Hierarchy].[Day])

the latter could be done using the filter() function e.g. filter([Product Dimension].[Product Type Hierarchy].[Product Type], roleValue('_memberCaption', currentMember([Product Dimension].[Product Type Hierarchy])) contains 'camping')

Page 22: Cognos Tips

Filtering along a dimension not present in the crosstab...to continue the example above you may only want to display sales that were done by a certain branch. Branch does not appear on the axes of the crosstab... so again filter may seem like a good idea. What you really want to do here is to tune the measure that gets displayed. when you drag-and-drop a measure in Report Studio is really translates to something like value(tuple([measure]))This tuple is incomplete, and will use currentMember() for dimensions that are present in the context and defaultMember otherwise.e.g.value(completeTuple([Sales Total], currentMember([Product Dimension].[Product Type Hierarchy].[Product Type]), currentMember([Time Dimension].[YMD Hierarchy].[Date], defaultMember([Branch Dimension].[Location Hierarchy].[Branch])))

The default member is the "all" at the top... in other words the Sales Total will be rolled up and you get the sum of sales done in all the branches. Instead of using a filter you need to tweak the tuple expression to use something other then the defaultMember()e.g.tuple([Sales Total], [Branch Dimension].[Location Hierarchy].[Branch]->?Branch?)will translate tovalue(completeTuple([Sales Total], currentMember([Product Dimension].[Product Type Hierarchy].[Product Type]), currentMember([Time Dimension].[YMD Hierarchy].[Date], [Branch Dimension].[Location Hierarchy].[Branch]->?Branch?))

Filtering based on some attributes of the factsThis is the last scenario I can think of ... this is when it goes wild.You want to apply a filter to the whole thing. e.g. only count sales where the customer payed in US dollars. You don't have a dimension but you know that you facts do have an attribute that you could use to build a filter.e.g. Somewhere you had a Sale record with a CurrencyUsedToPay field.

What really happened here is... you missed to create a dimension.

If you use DMR a filter would probably work... it's just not god design. If you use real OLAP then everything is preaggregated... it's too late to try to filter the facts. You need to revisit the design of your Sales Total cube.

Page 23: Cognos Tips

One last though about DMRNot only is the use of filters "not nice"... often it can give you incorrect results. To return to our first scenario... if you filtered product types using filter and one day you want to add a new row to your crosstab to display the sales total for all product types... you would be in trouble.

Sales Total 1/1/2007 ... 04/21/2008 04/22/2008

Camping Equipment

1,000$ ... 1,000$ 1,000$

... ... ... ... ...

Product Types (All)

... ... ... ...

The way Cognos processes the filter would add a WHERE clause to the SQL SELECT. At the end "all product types" would become "all the selected product types".

ConclusionThe Cognos Report Studio GUI does not distinguish between relational and dimensional models. It always looks the same. This is misleading because certain features should only be used when working with one type of model and not the other.In case of DMR it's even worse because Cognos tries to interpret these (filter, join, usion) wvwn though it conceptually does not make sense. Sometimes you get what you wanted but often not.

In my opnion detail or summary filter should only be used when working with a relational model. Posted by Tamas Simon (Sic) at 9:51 AM 7 comments Links to this post

Sunday, April 20, 2008custom roles do not wok I tried setting custom roles in a DMR model. The feature is a total screw up. It just simply does not work.The roleValue() function does not return an error when I set the role string to something dummy... a role that does not even exist. If just did not return anything.This would be OK.The bigger problem is that even when I set it to a proper role type that was created in the model it still does not return anything.

Conclusion: forget custom roles, at least for DMR.

ps My understanding is that DMR was the only kind of model where custom roles should be used at all.

Page 24: Cognos Tips

Posted by Tamas Simon (Sic) at 12:21 AM 0 comments Links to this post Labels: custom roles type

Friday, April 18, 2008prompts explained Prompts provide a way to dynamically change the reports.

In other words their function is to "show only this", "show only that', "show between this day and that day".

I think it would be fair to say that a prompt is what appears on the screen and a parameter is a programming variable that stores the users choice.

So prompts and parameters are very closely related, they are practically the same.

A prompt appears minimum in two places. On the prompt page - where we get the value - and in an expression - where we use the value. (Otherwise it would not make sense...)If a prompt appears in an expression but you forgot to put it on the prompt page then it will be autogenerated by Cognos. You don't want this... it's much better to have control over the prompt page.

However it can appear in more than two places as it gets used in expressions and even in the model. If you use DMR it is a good idea to use prompts in the model because you can optimize the performance. e.g. If the user selects only a single branch of a bank then there is no need to calculate all metrics for every branch, you can use the prompt in the model to set a filter on the queries... and everything will run faster.

There are a few important things about prompts that are not obvious from the documentation:

1. In Report Studio you can use the same #prompt()# function as in Framework Manager. (Actually you can use all macro functions.) What you see - what the editor offers - ?Parameter1? is just a shorthand for #prompt('Parameter1', 'string')#

2. You need to refer to prompts in exactly the same way everywhere, in expressions and on the prompt page. Otherwise Cognos gets confused. Thisnk about this when you set a prompt as "required" but its not, or when the prompt pop up again even though it already appeared on the prompt page.

Page 25: Cognos Tips

The property settings should match how the #prompt()# macro is called. 

3. For a prompt being optional is the same thing as having default value. If a prompt has default value then it is optional.If a prompt is optional it must have a default value. The only exception is to set the default selection property in Report Studio and set the prompt as required; and then in the expressions not setting a default value. This way the prompt is required and the prompt page can provide the value set as default if you hide the prompt. - This technique allows you to do some tricks...

4. Remember: prompt is a macro. It is just a string replacement. Whatever appears between the hashmarks will be replaced and then the expression will be evaluated.If you get an error you can usually see what the prompt macro was replaced with.You can also debug the report by droppin a Text Item, setting its source to "Report Expression" and setting the expression to something like ParamValue('parameter1')- do not use ParamDisplayValue() .. use ParamValue()

5. Since the prompts will be used in different expressions you get most freedom by setting the prompt type to "token". This way the replacement value won't have quotation marks around it. This is useful. Check the other macro functions such as split(), sq() to build a string from the prompt as needed.

6. Keep in mind the promptmany() function. It is practically the multi-selection prompt.If you want the prompt to handle multiple values then you need to use this version. 

Working with prompts using a dimensional model

The prompt can return the parameter value in a number of ways: string, date, token, MUN (Member Unique Name).

If you don't know what MUN is please read the documentation; it is important. It's basically a string identifier for a member of a dimension. It's an ID... plus some extra that helps to figue out what the ID is for. 

When working with dimensional model you want to build a member set from the prompt selection... pretty much always. 

Page 26: Cognos Tips

If you think you only need to build a filter expression please think twice.For a DMR model I'm pretty sure filters should not be used - at all.and I have the same feeling for an OLAP based dimensional model.So, forget filters. They are for the people still in the kindergarden who use relational models for BI.All you want to do is to say which members should appear in a crosstab (or chart) based on the users selection. What you need is a member set.

To build a member set the "string" type of prompt is useless because it is surrounded by single quotes which does not play well with the MUN (Member Unique Name) format.Either you can get the MUN directly from the prompt() function or you need to build it yourself. In this case "token" is better. It's the same value being returned as when using "string" only without the quotes.

I find that using the question mark shorthand: ?Parameter1? is the same as #prompt('Parameter1', 'string')#Frankly I'm not 100% sure... but I still prefer using the macro format to be certain of what I'll get.

The easiest thing to build a memberset is to do this:set( #promptmany('Parameter1', 'MUN' )# )It gets challenging when you want to make the prompt optional.If you only return an empty string or a space then after the prompt is processed the expression will look like set( ) ... which Cognos does not like and gives you an error.Instead use the emptySet function as the prompt's default valuet:set( #promptmany('OptionalParameter1', 'MUN', emptySet([my_dimension].[my_hierarchy])# )To have the prompt return MUN you need to set the "Use Value" of its query to a dimension level.

The other option is to build the MUn yourself in the expression. If the MUN has only one ID then it's simple. Something like [my_dimension].[my_hierarchy].[my_level]->[all].#sq(prompt('parameter1','token'))#

With DMR model it is often not the case... even if you set a level as "Uniquely Identified" Cognos still includes the business keys of all upper levels in the MUN... which makes it difficult - almost impossible - to build MUNs.(I think it is a bug in Cognos DMR.)You can only do it if you prompt the dimension members themselves. then Cognos will do it.

Page 27: Cognos Tips

Otherwise... not.e.g. If you have a hierarchy in the time dimension it can become difficult. Because you want a date prompt - which is not built from the dimension. It's just a calendar.That's OK... you don't want to use DMR anyways. It sucks. Use real OLAP and take control of how the MUNs are generated.

I figured that with the promptmany function using tokens they are separated by semicolons.start with #split(';', promptmany('Parameter1', 'token'))# and use the substitute macro to build a lst of MUNs.

Time filtering: From and To

Often you want to run the report for a specified time interval. this is not at easy as it seams.If you find that a simple filter is not working for you.. and remember, IMO you should never use a filter... then you'll appreciate this tip as building a member set containing all dates between "from" and "to" gets quite challenging.filter([Time Dimension].[My Hierarchy].[Date],roleValue('_businessKey', currentMember([Time Dimension].[My Hierarchy])) >= #sq(prompt('From', 'Date'))# and roleValue('_businessKey', currentMember([Time Dimension].[My Hierarchy])) <= #sq(prompt('To', 'Date'))#)i know it's crazy... but this will save you 2 days minimum.

we're using the filter() function to "build" the member set - by taking away unwanted members.

we rely on the fact that dates as string can be still compared and will maintain the same order as the dates

note that roleValue() returns the selected attribute as a string, regardless of the attribute's type - which is date in this example

I'll write a post about why filtering should be avoided... so hopefully I'll convince you that I'm not crazy and all this overcomplicated crap is necessary for real life reporting... I mean something other than GO Sales :)

Posted by Tamas Simon (Sic) at 9:46 PM 14 comments Links to this post Labels: prompt, promptmany

Page 28: Cognos Tips

Thursday, April 3, 2008substitute() macro It's not documented anywhere so here you go:

^ matches the beginning of the string$ matches the end of the string

Multiple substitute() calls can be nested into one another.

e.g. to put a string into square brackets you could write

substitute('^', '[', substitute('$', ']', '_string_goes_here')) Posted by Tamas Simon (Sic) at 11:16 AM 1 comments Links to this post

Thursday, March 27, 2008filter vs tuple why should you use tuple() and not filters.

First of allyou can only use one filter... but you can write as many tuple expressions as you want.

e.g. Sales is a measure and you want to get its value on 1/1/2008 and 3/1/2008 How would you do it with a filter? One would make the second impossible.With tuple expressions you can create calculated data items and call them something like Sales_on_1/1/2008 and Sales_on_3/1/2008

tuple([Sales], [Time Dimension].[date hierarchy].[date]->[2008-01-01])

But I have an even better reason!

Cognos user interface does not distinguish between relational and dimensional or DMR model.You should!What does a filter mean when working with a dimensional model?Who the hell knows.I think with DMR they (Cognos) add a where clause to the generated SQL... so something will happen... it's just ugly. See how your higher level aggregates will behave...using tuples() is way more clear!

TUPLE RULEZ!

Page 29: Cognos Tips

good nite!Posted by Tamas Simon (Sic) at 1:22 PM 5 comments Links to this post

Friday, March 14, 2008Macro functions - undocumented feature in Report Studio Did you know that you can use the same macro functions that you have in Framework Manager in Report Studio?

It's not documented in the Report Studio users guide and the GUI which lists the available functions doesn't suggest it either.

Yet, they are there!

Try writing an expression where instead of ?Param1? you write #prompt('Param1')# ... there you go.

This lets you use some very powerful tricks when working with a dimensional model.Some of which I'll describe later... Posted by Tamas Simon (Sic) at 9:44 AM 0 comments Links to this post

Wednesday, March 5, 2008How do charts work like crosstabs I found the graphical interface of charts rather challenging to capture but once you understand that they work exactly like crosstabs you can figure it out:

measure (y-axis) = Deafult MeasureSeries = vertical axisCategory (x-axis) = horizontal axis

note that just like a crosstab axis can nest one dimension into another, or add measures on the axis you can do the same in the chart

example crosstab:

note the nesting of Revenue and Gross Profit under RetailerandProduct type under Month(Time)

Page 30: Cognos Tips

the corresponding chart:

note: we have the same nesting

when we run the report the chart will look like this:

Page 32: Cognos Tips

note: the legend explains the color coding for each combination of retailer and revenue or retailer and profit

whether this complex chart makes sense is a good question... sometimes it does, sometimes it doesn't... the point is: you could if you wanted! Posted by Tamas Simon (Sic) at 5:12 PM 0 comments Links to this post

Tuesday, March 4, 2008How to use prompt values in a tuple expression This golden nugget can save you 2 days of work - that's how long it took me to figure out the syntax.

In the tuple() you can use a member to specify which value of the measure you want. This will work much like a filter... just better.

Lest say you have a Sales measure and a Time dimension with Date at the lowest level.

You can write something like this:

tuple([Sales], [Time Dimension].[Date hierarchy].[Date]->[all].[1/1/2008])

this will get you the Sales on 1st Jan. 2008

This is great, but you want to make this a parameter, so the user can specify the date.

Page 33: Cognos Tips

Maybe you have a reporting interval called ?ReportStart? and ?ReportEnd? and you want to get the Sales on the last day of the reporting interval.

You can do this:

tuple([Sales], [Time Dimension].[Date hierarchy].[Date]->[all].#sb(prompt('ReportEnd','date'))#

You can use this expression in a crosstab or graph to give you the Sales measure on the end of the reporting interval.

In more generic terms this is the syntax to use prompt parameters in tuple() expressions.Posted by Tamas Simon (Sic) at 11:28 AM 1 comments Links to this post Labels: crosstab, prompt, tuple

Monday, March 3, 2008Cognos UI I found that Cognos uses the same user interface when working on dimensional (including DMR) and relational model.This causes a lot of confusion because the two work totally different.To further worsen things there is no error message when you do something that... you just should not do. Even worse... you get some results. But who know what those are! Posted by Tamas Simon (Sic) at 10:09 AM 0 comments Links to this post

Friday, February 29, 2008How to write a report on a dimensional model - part3 Today (tonight actually) I'll attempt to make some further clarifications about how crosstabs work.

For simplicity's sake in part2 I mentioned that along the axes of the crosstab we place ``dimensions''.

In fact these are member sets.

A member set is simply a set of members.When you drag a dimension - Cogno calls it "regular dimension" - what really happens is that it will be coerced into its members. Search the Cognos documentation for Coersion Rules.The point I'm trying to make is that you are not limited to working with dimensions. You can use 

expressions that return a set of members a certain member (e.g. a given month in the Time hierarchy)this

member will be implicitly casted to a member set with one element only

Page 34: Cognos Tips

memberset that is defined by you by picking any set of members you wantSearch the Cognos documentation for Defining Member Sets

Another clarification about measures.I think Cognos uses values for measures and these values are evaluated for every cell using tuple() function.In other words you can have calculated measures by doing some arithmetic on tuples.A usual scenario is a "smart" average calculation :average_daily_something:= value(tuple(some_value_measure)) / value(tuple(some_days))

For example you want to get the average daily sales amount for a time period but the store is not open on weekends.

Sales - measureTime - dimension

on weekends Sales will be equal to 0 but you don't want to count this into your daily average

you could do something like

Add a Workday measure that is 1 for workdays and 0 for weekends.avg_daily_sales := value(tuple(Sales)) / value(tuple(Workday))

You'll come up with measure calculations that make sense in your business... the point is that in your forulas you can use value(tuple(...)) as operands and then use this "calculated measure" in the crosstab.

Posted by Tamas Simon (Sic) at 12:36 AM 0 comments Links to this post

Wednesday, February 27, 2008Thinking out louad about Cognos Framework Manager I've been thinking about Cognos Framework Manager.I think it's anoher overhyped thing.

Sure it can store meta-data that tells Cognos how to join tables, how to generate queries.But wait a sec!

Page 35: Cognos Tips

What are the options here?

1. Relational modelDo you really want to create a data warehouse from a relational model? Come on!

2. DMR modelThis would make some sense... if it wasn't such a poorly implemented feature of Cognos that I can only recommend to avoid it if possible.

3. OLAP cubesIn this case the framework doesn't do much, just connects to the cube.

So what's the big deal then? Posted by Tamas Simon (Sic) at 2:22 PM 2 comments Links to this post Labels: Cognos Framework Manager

How to write a report on a dimensional model - part2 This is part 2 of my little essay about how to get the values that you want show up on the report where you want them. The first part  talked about the tuple() function. If it wasn't clear enough, it will be... Crosstabs and tuple() are so related it's difficult to explain one without the other.

If you've used pivot tables in Excel then roughly that's what you can expect from a crosstab.Crosstab is a table with values in the middle and headers along the edges. These headers can be 

labels for the numbers we see in the middle of the table members of a dimension so that we give some context to those

numbers.

Tables are the best way to "flatten" the dimensional data since most of us are not comfortable looking at 5 dimensional Rubik cubes :)

Crosstabs do provide a way for displaying multi ( > 2) dimensional data in a way that we can digest.I'll provide examples going from the simplest case towards the more difficult.

A crosstab axes contains either a member set or a tuple() expression. (Even when it looks just like a simple measure.) Member sets are "expanded" during runtime - thereby creating

Page 36: Cognos Tips

multiple rows or columns. tuple() expressions are evaluated for every cell in the row or column.

I will use the same example as in part one:Sales - measureBranch, Product, Time - dimensions

1., one dimension - one measure

measure   |----------+-------dimension1| <1234>

The crosstab will work much like a simple list. When you think you need only a list use this instead. Lists are not meant for dimensional model.

You may notice that the horizontal axes is left empty. That's OK.

The upper left corner of the crosstab ddisplays the default measure. You can drag a measure there or into the "content" area.Most people get confused by this and think that the crosstab can only display one measure.It's not true. As you can see later a crosstab can display as many measures as you want.

The default measure is used to evaluate tuple() expressions where the measure is not specified.I'll show examples of that later. Just keep it in mind.

e.g.

Sales |------+-------Branch| <1234>

"Sales" really becomes tuple(Sales)

Sales                    | -------------------------+---------Richmond AutoMall        | 450,000-------------------------+---------North Vancouver AutoMall | 129,000-------------------------+--------- Kingsway Nissan          |  39,000-------------------------+---------

Page 37: Cognos Tips

The dimension is expanded.The tuple expression is evaluated in the context of the crosstab like thistuple(Sales, currentMember(Branch), defaultMember(Time), defaultMember(product))

The defaultMember practically means Product and Time resulting in rolled-up values along these dimensions.

2., two dimensions - one measure

measure    | dimension1-----------+-----------dimension2 | <1234>

This is the "classical" crosstab.

e.g.

Sales | Time------+------Branch| <1234>

Note that "Sales" is still tuple(Sales)that gets evaluated liketuple(Sales, currentMember(Branch), currentMember(Time), defaultMember(Product))

Both dimensions will be expanded resulting in something like this:

Sales                    | 1/1/2008 | ... | 1/31/2008-------------------------+----------+ ... +----------Richmond AutoMall        | 20,000            17,000-------------------------+----------+ ... +----------North Vancouver AutoMall | 23,000                 0-------------------------+----------+ ... +----------Kingsway Nissan          | 18,000            24,500

3., one dimension - many measures

The crosstab can have multiple measures. One of them is the default.

measure1   | measure1 | measure2  ...  measure_n-----------+----------+---------+ ... +---------dimension1 | <1234>   | <1234>  | ... | <1234>

Page 38: Cognos Tips

In this example measure1 is the default measure.

Having a default measure we can do something like this:fusion_sales := tuple([Product]->[Ford Fusion])

Sales  | Sales | fusion_sales-------+-------+-------------Branch | <1234>| <1234>

Note that the tuple() expression only specified the product dimension.Cognos will figure out from the context that we are talking about Sales; because Sales is the default measure.fusion_sales will be evaluated like this:tuple(Sales, currentMember(Branch), defaultMember(Time), [Product]->[Ford Fusion])

It will give the total of Ford Fusion sales per branch.

The arrow ``->'' is Cognos's notation for specifying a member.Try dragging in a member from a dimension... you'll see.  

(It's a powerful tool to create "custom measures" so to speak. So we won't have "ford Fusion Sales" as a separate metric in our cube..)

4., three or more dimensions - one measure

When we need more than 2 dimensions we have to nest them into one another.

measure                 | dimension3------------------------+-----------dimension1 | dimension2 | <1234>           +------------+-----------           | dimension2 | <1234>-----------+------------+-----------

e.g.

Sales            | Time-----------------+-------Branch | Product | <1234>       +---------+-------       | Product | <1234>-------+---------+-------

Page 39: Cognos Tips

as the dimensions are expanded all combinations will be created

Sales                                    | 1/1/2008 ...-----------------------------------------+---------Richmond Autmoall        | Ford Fusion   |                          +---------------+---------                         | Nissan Maxima |                         +---------------+---------                         | Honda Civic   |-------------------------+---------------+---------North Vancouver Automall | Ford Fusion   |    *                         +---------------+---------                         | Nissan Maxima |                         +---------------+---------                         | Honda Civic   |

* Sales of Ford Fusion at North Vancouver Automall on 1st Jan

Note how the nested dimension (Product) is repeatedly expanded for every member of the outer dimension (Branch).

5., many dimensions  - many measures

Using nesting you can go wild!

Measure1                | dimension1          |                        +---------------------+                        | measure1 | measure2 |------------------------+----------------------dimension2 | dimension3 | <1234>   | <1234>   |           +------------+----------+-----------           | dimension3 | <1234>   | <1234>   |           +------------+----------+----------+            

In the next part I'll show some practical examples and talk about member sets.Just to wet your apetite... think about not having the entire dimension along the axes, only some specific members you want...Posted by Tamas Simon (Sic) at 12:29 AM 0 comments Links to this post Labels: crosstab, tuple

Tuesday, February 5, 2008Data level security filter - challenge Cognos lets you put a security filter on the data.This lets you limit who can see what.

How about a more complex case... when users can see aggregate data

Page 40: Cognos Tips

of higher levels but are only allowed to see certain members of a lower level.

e.g.Sales is a measure that is associated with a Branch dimension.

Users from each branch are allowed to see the sales of their own branch and the aggregated total sales accross all branches - ``Branch(ALL)'' as Cognos calls it.If we put a security filter on the Branch dimension or the Sales measure then we filter out all the data, so the aggregate value will only show one branch.(At least that's what's gonna happen with a DMR model.)What should we do?

I couldn't figure out a good answer for this problem other than not having data level security in the model.The security can be implemented in the reports by enforcing some prompt based filter and limiting the selections based on the user's access etc.This won't help much if you're willing to use tools like Analysis Studio where the user can directly interact with the model.Posted by Tamas Simon (Sic) at 1:48 PM 2 comments Links to this post Labels: security

Friday, February 1, 2008How to write a report on a dimensional model - part1 by using crosstabs and the tuple() function of course!

Let me show you how...

First of all: what is a tuple?Tuple is basically the way to address a value in an n-dimensional array, the OLAP cube.It's basic form is simple:tuple(measure, dimension1, dimension2,...)

Tuple is really a coordinate.To get the value of the cube at this coordinate we need to use the value() function.value(tuple(measure, dimension1, dimension2,...)Cognos does this automatically. Search for Coersion Rules in the Report Studio users guide.It's good and bad... makes things easier, but causes confusion too... anyways.

Page 41: Cognos Tips

In order to specify our coordinate we need to specify a member in each and every dimension that applies to the measure.

We don't need to write it all however. Cognos fills in the missing values but it is very important to understand how...

measure: defaults to the "default measure" - see upper left corner of crosstab

dimension: defaults to the current member of the dimension coming from the context - i.e. if the dimension appears on one of the axes in the crosstab, otherwise defaults to the default memberThe default member is the root "(All)" member. By defaulting to this we are in effect rolling up that dimension. In other words dimensions that are not in the context of the crosstab are rolled up. Makes perfect sense.

If you don't want this default behavior you can just edit the expression and specify exactly what you want. This is very cool, it's the most powerful tool a report writer has.

exampleSale is a measure that is associated with three dimensions:- Time- Product- Branch

to fully specify a sale we need to supply a member of all three dimensions:Sale(1/23/2008, 'ford fusion', 'Richmond Automall')

tuple(Sale) will add up all the sales tuple(Sale, 1/23/2008) will add up all the sales on Jan 23 for all products at all branches tuple(Sale, 'ford fusion') will add up all the sales where the product was a Ford Fusion etc.

We need to understand that the tuple is executed in the context of a crosstab.Dimensions that are not explicitly mentioned will be searched for among the axes to see if they have a current member.This gives a whole new meaning to the examples above... Taking the last example for instance:

tuple(Sale, 'ford fusion') | Time

Page 42: Cognos Tips

---------------------------+------Branch                     | <1234>

This crosstab has Branch and Time along the axes which will suply the context for the tuple expression. This crosstab will display the Ford Fusion sales broken down per day and per branch.

If we don't want our expression to depend on the context of the crosstab we can use the completeTuple() function.Every dimension that is not explicitly defined will default to its default member - meaning it will be rolled up.

In the next part I'll write about crosstabs. Using tuple() expressons in crosstabs you can do pretty much anything.

And here is the good news. Charts work exactly like crosstabs.If you can get the data to show up in a crosstab you can create a chart plotting the same data by setting it to the same query.

By the way... forget about list. When you work with a dimensional model you don't need list.Posted by Tamas Simon (Sic) at 12:32 AM 1 comments Links to this post Labels: crosstab, memberset, tuple

Scope Scope is a tricky term to understand and in my opinion is not properly done - at least not in DMR.

IMO scope is the lowest level of granularity in a hierarchy for a measure's value.If we want a value for higher levels then we roll up.

Cool. What about lower levels?Cognos does not give any value for lower levels.

I think it's wrong. They mix access with granularity. You do not have access to measures that are not in scope. What the heck? You are taking away my access? For what?I think the value should just be repeated, propagated down to lower levels.

Let me explain by an example.

Let's say we have an Annual Sales Target that is defined for each year. Our Time Dimension has the usual levels: Year, Month, Date

Page 43: Cognos Tips

It wouldn't make sense to associate a value of Sales Target with the Date or Month level.

every day or month would have the same value it is an annual target, we need to compare it with a year's worth

of sales anyways how would we roll it up for a year?

so everything tells us that it should be set in scope for the Year level only.Right.Now what if I ask the question: What was the annual sales target on Jan 23, 2008?Cognos won't supply a value.Is this question meaningful? We need to roll-up the sales for an entire year before we can do anything meaningful, don't we? So we don't really need a value at the day level... do we?

How about this: for each day I want to calculate the rolling-total of sales for 365 days back in time; and then compare that with the annual sales target. So as the year progresses I'd have some idea if I'm on track. Now that would make sense!

Unfortunately Cognos doesn't work like this.

Moving the Annual Sales target to the lower levels in scope is a bad idea - remember our reasons for putting it at the year level?

Tip:When you need a value at a lower level than its scope you can use a tuple(), parent() and currentMember() to get the valuee.g. this expression would work at the day level:tuple([Annual Sales Target], parent(parent(currentMember([Time Dimension]))))

I like Python's philosophy: discourage bad behavior but do not prevent it.Why are they preventing me from accessing the value from a higher level? Let me decide if it makes sense to use it!

Posted by Tamas Simon (Sic) at 12:05 AM 0 comments Links to this post Labels: scope

Thursday, January 31, 2008How list works

1. runs the query, gets the reultset

Page 44: Cognos Tips

2. looks at all the columns (query items) and check the usage attribute

3. it will distinguish between facts and everything else: attributes and identifiers

4. makes sure that there is only one row for each unique combination of attributes and identifiers

5. when multiple rows are found these are groupped by aggregating all the facts

This means you have to be extra careful to make sure that the usage attribute is set properly.Usually it is... but there's no guarantee.If you see too many rows or values being summed up then keep this in mind. Posted by Tamas Simon (Sic) at 11:54 PM 0 comments Links to this post

List vs Crosstab It's easy. But I haven't found it mentioned clearly in Cognos documentation or training:Use List for relational model, Crosstab for dimensional model.

This means that if you are using Cognos in a real data warehouse scenario you can most certainly forget about lists.

The good news: Everything you can do with list can be done

with crosstab (so you won't miss it)including having only one dimension

if you can get it working in crosstab then you can plot it on a graphgraphs work exactly like crosstabs

Posted by Tamas Simon (Sic) at 11:44 PM 1 comments Links to this post Labels: crosstab, list

DMR feature DMR model stands for Dimensionally Modelled Relational model.

It's a new feature that was added in the latest version of Cognos I

Page 45: Cognos Tips

believe. As such... it's immature.

When should you use it?DMR can be useful when you have a phisical star schema but you don't have an OLAP cube yet.It allows you to build a "virtual cube" in Framework Manager.From the report's perspective the model behaves like a "normal" dimensional model.

There are a couple of things wrong with it though...

The order of members in leves (of hierarchies within dimensions) is not guaranteed. this is documented in the know issues.What this means is that e.g. there's no guarantee that dates are coming out in order of the time dimension. They can get mixed up. Certain functions that depend on the order of members - such as nextMember() - are not suggested for use.Tip:I found that you can work around this issue by explicitly setting the order of element in the report by setting sorting on the dimensions in crosstabs.

Even though it supposed to look like a dimensional model from a report you don't see any MDX. When you try to look at the generated query in Report Studio it shows you SQL.This makes it very confusing. I've seen lot of developer still applying the "relational thinking" when working with a DMR model. And that doesn't work...Tip:Remember that you are working with a dimensional model. The queries that get generated by Report Studio are not relational queries - even though they look like that. they are really just collections of dimensional expressions that say how to get values from the "virtual cube" to populate the axes of crosstabs or graphs and how to get values for measures.In a later post I'll explain how to work with dimensional model from reports.Tip:Don't work with the queries... don't UNION them, JOIN them or anything like that. Relational thinking just won't work.

It is quite tricky to set up dimensions in the model - Cognos calls it "regular dimension".When you set up levels the underlying query subject needs to have determinants, otherwise it will get screwed up.Determinants are the most horribly documented feature of Cognos

Page 46: Cognos Tips

IMO...

Another weird thing is that there's no guarantee that the lowest level is the same when you set up multiple hierarchies. What the heck? I think it always whould be the same.

e.g. product has size and colorSize hierarchy: Size level and Product levelColor hierarchy: Color level and Product level

There is no guarantee that the two product levels are the same. In fact I'm not sure Cognos even knows these two are the same...It's weird to me. I think the lowest level should always be the same and the editors used t set it up should enforce it.

That's about DMR for now. I hope it helps.