Being a business intelligence consultant, I like to spend my time designing data warehouses, ETL scripts and OLAP cubes. An unfortunate consequence of this is having to write the documentation that goes with the fun techy work. So it got me thnking, is there a slightly more fun techy way of automating the documentation of OLAP cubes…
There are some good tools out there such as BI Documenter, but I wanted a way of having more control over the output, and also automating it further so that you don’t have to run an overnight build of the documentation.
I found a great article by Vincent Rainardi describing some DMVs (Dynamic Management Views) available in SQL 2008 which got me thinking, why not just build a number of SSRS reports calling these DMVs, which would then dynamically create the cube structure documentation in real time whenever the report rendered..
This post is the first in a 3 part set which will demonstrate how you can use these DMVs to automate the SSAS cube documentation and user guide.
- Part 1 – Creating the DMV stored procs
- Part 2 – Create the SSRS reports
- Part 3 – Use spatial data and maps to create a star schema view
- Download Source Code
UPDATE: I presented a 1 hour session at SQLBits 8 covering all of this work, you can watch the video here.
There’s a full list of DMVs available in SQL 2008 R2 on the msdn site.
The primary DMVs that are of interest are:
| DMV | Description |
| MDSCHEMA_CUBES | Lists the cubes in an SSAS database |
| MDSCHEMA_MEASUREGROUPS | Lists measure groups |
| MDSCHEMA_DIMENSIONS | Lists dimensions |
| MDSCHEMA_LEVELS | Dimension attributes |
| MDSCHEMA_MEASUREGROUP_DIMENSIONS | Enumerates dimensions of measure groups |
| MDSCHEMA_MEASURES | Lists measures |
When querying DMVs we can use SQL style SELECT statements, but executed against the cube in a DMX window.
SELECT * FROM $SYSTEM.MDSCHEMA_CUBES
This returns a dataset like any other SQL query.

We can even enhance it with DISTINCT and WHERE clauses, although they are more restricted than basic SQL. One of the main limitations is the lack of a JOIN operator. A number of the queries that I’ll perform below need to use JOIN, so to get around this I wrap up each query in an SQL OPENROWSET command, executed against a SQL database with a linked server to the cube. This enables me to perform JOINs using queries such as
SELECT *
FROM OPENQUERY(CubeLinkedServer,
'SELECT *
FROM $SYSTEM.MDSCHEMA_MEASUREGROUP_DIMENSIONS') mgd
INNER JOIN OPENQUERY(CubeLinkedServer,
'SELECT *
FROM $SYSTEM.MDSCHEMA_MEASUREGROUPS') mg
ON mgd.XXX = mg.XXX
etc.
I’m therefore going to create a number of stored procs to wrap up this functionality, the SSRS reports can then just call the procs.
Within BIDS, every item (cube, measure group, measure, dimension, attribute, hierarchy, KPI, etc.) has a description in the properties pane which is a multi-line free text property. These are exposed by the DMVs, so I’m going to make use of them and bring them out in the reports. This allows you to create the descriptions within BIDS as you’re developing the cube, meaning they’re version controlled and always in sync with the code.
I should also point out that I’m using SQL Server 2008 R2. All of the queries below will work with SQL 2008, but I want to use the spatial report functionality of SSRS 2008 R2 to generate dynamic star schema visualisations, which is only supported in R2.
In this post I’ll script out the stored procedures used as the basis of the documentation. In my next post I’ll put these into SSRS reports.
Lets get started.
Firstly we need to create our linked server. This script will create a linked server called CubeLinkedServer pointing to the Adventure Works DW 2008R2 OLAP database on the local server.
EXEC master.dbo.sp_addlinkedserver @server = N'CubeLinkedServer', @srvproduct=N'MSOLAP', @provider=N'MSOLAP', @datasrc=N'(local)', @catalog=N'Adventure Works DW 2008R2'
You’ll have to set up the security according to your requirements. So now lets start creating the source procs.
The first proc lists all of the cubes. The MDSCHEMA_CUBES DMV returns not only cubes, but also dimensions, I’m filtering it to only return cubes by specifying CUBE_SOURCE=1.
CREATE PROCEDURE [dbo].[upCubeDocCubes]
(@Catalog VARCHAR(255) = NULL
)
AS
SELECT *
FROM OPENQUERY(CubeLinkedServer,
'SELECT *
FROM $SYSTEM.MDSCHEMA_CUBES
WHERE CUBE_SOURCE = 1')
WHERE CAST([CATALOG_NAME] AS VARCHAR(255)) = @Catalog
OR @Catalog IS NULL
GO
The next proc returns all measure groups found within a specified cube.
CREATE PROCEDURE [dbo].[upCubeDocMeasureGroupsInCube]
(@Catalog VARCHAR(255)
,@Cube VARCHAR(255)
)
AS
SELECT *
FROM OPENQUERY(CubeLinkedServer,
'SELECT *
FROM $SYSTEM.MDSCHEMA_MEASUREGROUPS ')
WHERE CAST([CATALOG_NAME] AS VARCHAR(255)) = @Catalog
AND CAST([CUBE_NAME] AS VARCHAR(255)) = @Cube
GO
This next proc returns a list of measures within a specified measure group.
CREATE PROCEDURE [dbo].[upCubeDocMeasuresInMeasureGroup]
(@Catalog VARCHAR(255)
,@Cube VARCHAR(255)
,@MeasureGroup VARCHAR(255)
)
AS
SELECT * FROM OPENQUERY(CubeLinkedServer,
'SELECT *
FROM $SYSTEM.MDSCHEMA_MEASURES
WHERE [MEASURE_IS_VISIBLE]')
WHERE CAST([CATALOG_NAME] AS VARCHAR(255)) = @Catalog
AND CAST([CUBE_NAME] AS VARCHAR(255)) = @Cube
AND CAST([MEASUREGROUP_NAME] AS VARCHAR(255)) = @MeasureGroup
GO
The following proc queries all dimensions available within a specified cube. I’m filtering using the DIMENSION_IS_VISIBLE column to only show visible dimensions.
CREATE PROCEDURE [dbo].[upCubeDocDimensionsInCube]
(@Catalog VARCHAR(255)
,@Cube VARCHAR(255)
)
AS
SELECT * FROM OPENQUERY(CubeLinkedServer,
'SELECT *
FROM $SYSTEM.MDSCHEMA_DIMENSIONS
WHERE [DIMENSION_IS_VISIBLE]')
WHERE CAST([CATALOG_NAME] AS VARCHAR(255)) = @Catalog
AND CAST([CUBE_NAME] AS VARCHAR(255)) = @Cube
GO
Then we can query all available attributes within a dimension. This DMV returns a bitmask field (LEVEL_ORIGIN) which defines whether the attribute is a key, attribute or hierarchy. I’m using bitwise AND (&) to split this into three seperate fields for ease of use. I’m also filtering out invisible attributes, as well as those with a level of 0. Level 0 is the [All] member of any attribute, which we can ignore for this purpose.
CREATE PROCEDURE [dbo].[upCubeDocAttributesInDimension]
(@Catalog VARCHAR(255)
,@Cube VARCHAR(255)
,@Dimension VARCHAR(255)
)
AS
SELECT *
, CASE WHEN CAST([LEVEL_ORIGIN] AS INT) & 1 = 1
THEN 1 ELSE 0 END AS IsHierarchy
, CASE WHEN CAST([LEVEL_ORIGIN] AS INT) & 2 = 2
THEN 1 ELSE 0 END AS IsAttribute
, CASE WHEN CAST([LEVEL_ORIGIN] AS INT) & 4 = 4
THEN 1 ELSE 0 END AS IsKey
FROM OPENQUERY(CubeLinkedServer,
'SELECT *
FROM $SYSTEM.MDSCHEMA_LEVELS
WHERE [LEVEL_NUMBER]>0
AND [LEVEL_IS_VISIBLE]')
WHERE CAST([CATALOG_NAME] AS VARCHAR(255)) = @Catalog
AND CAST([CUBE_NAME] AS VARCHAR(255)) = @Cube
AND CAST([DIMENSION_UNIQUE_NAME] AS VARCHAR(255)) = @Dimension
GO
The next proc returns measure groups with their associated dimensions. We have to join two DMVs together in order to get the description columns of both the dimension and measure group.
CREATE PROCEDURE [dbo].[upCubeDocMeasureGroupsForDimension]
(@Catalog VARCHAR(255)
,@Cube VARCHAR(255)
,@Dimension VARCHAR(255)
)
AS
SELECT
mgd.*
, m.[DESCRIPTION]
FROM OPENQUERY(CubeLinkedServer,
'SELECT
[CATALOG_NAME]
, [CUBE_NAME]
, [MEASUREGROUP_NAME]
, [MEASUREGROUP_CARDINALITY]
, [DIMENSION_UNIQUE_NAME]
FROM $SYSTEM.MDSCHEMA_MEASUREGROUP_DIMENSIONS
WHERE [DIMENSION_IS_VISIBLE]') mgd
INNER JOIN OPENQUERY(CubeLinkedServer,
'SELECT
[CATALOG_NAME]
,[CUBE_NAME]
,[MEASUREGROUP_NAME]
,[DESCRIPTION]
FROM $SYSTEM.MDSCHEMA_MEASUREGROUPS') mg
ON CAST(mgd.[CATALOG_NAME] AS VARCHAR(255))
= CAST(mg.[CATALOG_NAME] AS VARCHAR(255))
AND CAST(mgd.[CUBE_NAME] AS VARCHAR(255))
= CAST(mg.[CUBE_NAME] AS VARCHAR(255))
AND CAST(mgd.[MEASUREGROUP_NAME] AS VARCHAR(255))
= CAST(mg.[MEASUREGROUP_NAME] AS VARCHAR(255))
WHERE CAST(mgd.[CATALOG_NAME] AS VARCHAR(255)) = @Catalog
AND CAST(mgd.[CUBE_NAME] AS VARCHAR(255)) = @Cube
AND CAST(mgd.[DIMENSION_UNIQUE_NAME] AS VARCHAR(255)) = @Dimension
GO
The next proc is similar to the above, but the opposite way around. It returns all dimensions that are related to a measure group.
CREATE PROCEDURE [dbo].[upCubeDocDimensionsForMeasureGroup]
(@Catalog VARCHAR(255)
,@Cube VARCHAR(255)
,@MeasureGroup VARCHAR(255)
)
AS
SELECT
mgd.*
, d.[DESCRIPTION]
FROM OPENQUERY(CubeLinkedServer,
'SELECT
[CATALOG_NAME]
,[CUBE_NAME]
,[MEASUREGROUP_NAME]
,[MEASUREGROUP_CARDINALITY]
,[DIMENSION_UNIQUE_NAME]
,[DIMENSION_CARDINALITY]
,[DIMENSION_IS_VISIBLE]
,[DIMENSION_IS_FACT_DIMENSION]
,[DIMENSION_GRANULARITY]
FROM $SYSTEM.MDSCHEMA_MEASUREGROUP_DIMENSIONS
WHERE [DIMENSION_IS_VISIBLE]') mgd
INNER JOIN OPENQUERY(CubeLinkedServer,
'SELECT
[CATALOG_NAME]
,[CUBE_NAME]
,[DIMENSION_UNIQUE_NAME]
,[DESCRIPTION]
FROM $SYSTEM.MDSCHEMA_DIMENSIONS
WHERE [DIMENSION_IS_VISIBLE]') d
ON CAST(mgd.[CATALOG_NAME] AS VARCHAR(255))
= CAST(d.[CATALOG_NAME] AS VARCHAR(255))
AND CAST(mgd.[CUBE_NAME] AS VARCHAR(255))
= CAST(d.[CUBE_NAME] AS VARCHAR(255))
AND CAST(mgd.[DIMENSION_UNIQUE_NAME] AS VARCHAR(255))
= CAST(d.[DIMENSION_UNIQUE_NAME] AS VARCHAR(255))
WHERE CAST(mgd.[CATALOG_NAME] AS VARCHAR(255)) = @Catalog
AND CAST(mgd.[CUBE_NAME] AS VARCHAR(255)) = @Cube
AND CAST(mgd.[MEASUREGROUP_NAME] AS VARCHAR(255)) = @MeasureGroup
GO
The next proc builds a BUS matrix, joining every dimension to its related measure groups. Later we’ll use the SSRS tablix control to pivot this into matrix form.
CREATE PROCEDURE [dbo].[upCubeDocBUSMatrix]
(@Catalog VARCHAR(255),
@Cube VARCHAR(255)
)
AS
SELECT
bus.[CATALOG_NAME]
,bus.[CUBE_NAME]
,bus.[MEASUREGROUP_NAME]
,bus.[MEASUREGROUP_CARDINALITY]
,bus.[DIMENSION_UNIQUE_NAME]
,bus.[DIMENSION_CARDINALITY]
,bus.[DIMENSION_IS_FACT_DIMENSION]
,bus.[DIMENSION_GRANULARITY]
,dim.[DIMENSION_MASTER_NAME]
,1 AS Relationship
FROM
OPENQUERY(CubeLinkedServer,
'SELECT
[CATALOG_NAME]
,[CUBE_NAME]
,[MEASUREGROUP_NAME]
,[MEASUREGROUP_CARDINALITY]
,[DIMENSION_UNIQUE_NAME]
,[DIMENSION_CARDINALITY]
,[DIMENSION_IS_FACT_DIMENSION]
,[DIMENSION_GRANULARITY]
FROM $SYSTEM.MDSCHEMA_MEASUREGROUP_DIMENSIONS
WHERE [DIMENSION_IS_VISIBLE]') bus
INNER JOIN OPENQUERY(CubeLinkedServer,
'SELECT
[CATALOG_NAME]
,[CUBE_NAME]
,[DIMENSION_UNIQUE_NAME]
,[DIMENSION_MASTER_NAME]
FROM $SYSTEM.MDSCHEMA_DIMENSIONS') dim
ON CAST(bus.[CATALOG_NAME] AS VARCHAR(255))
= CAST(dim.[CATALOG_NAME] AS VARCHAR(255))
AND CAST(bus.[CUBE_NAME] AS VARCHAR(255))
= CAST(dim.[CUBE_NAME] AS VARCHAR(255))
AND CAST(bus.[DIMENSION_UNIQUE_NAME] AS VARCHAR(255))
= CAST(dim.[DIMENSION_UNIQUE_NAME] AS VARCHAR(255))
WHERE CAST(bus.[CATALOG_NAME] AS VARCHAR(255)) = @Catalog
AND CAST(bus.[CUBE_NAME] AS VARCHAR(255)) = @Cube
GO
Next, in order to make it easier for users to find items within the cube, I’ve created a searching proc which will scour a number of the DMVs for anything containing the search term.
CREATE PROCEDURE [dbo].[upCubeDocSearch]
(@Search VARCHAR(255)
,@Catalog VARCHAR(255)=NULL
,@Cube VARCHAR(255)=NULL
)
AS
WITH MetaData AS
(
--Cubes
SELECT CAST('Cube' AS VARCHAR(20)) AS [Type]
, CAST(CATALOG_NAME AS VARCHAR(255)) AS [Catalog]
, CAST(CUBE_NAME AS VARCHAR(255)) AS [Cube]
, CAST(CUBE_NAME AS VARCHAR(255)) AS [Name]
, CAST(DESCRIPTION AS VARCHAR(4000)) AS [Description]
, CAST(CUBE_NAME AS VARCHAR(255)) AS [Link]
FROM OPENQUERY(CubeLinkedServer,
'SELECT [CATALOG_NAME], [CUBE_NAME], [DESCRIPTION]
FROM $SYSTEM.MDSCHEMA_CUBES
WHERE CUBE_SOURCE = 1')
WHERE (CAST([CATALOG_NAME] AS VARCHAR(255))
= @Catalog OR @Catalog IS NULL)
UNION ALL
--Dimensions
SELECT CAST('Dimension' AS VARCHAR(20)) AS [Type]
, CAST(CATALOG_NAME AS VARCHAR(255)) AS [Catalog]
, CAST(CUBE_NAME AS VARCHAR(255)) AS [Cube]
, CAST(DIMENSION_NAME AS VARCHAR(255)) AS [Name]
, CAST(DESCRIPTION AS VARCHAR(4000)) AS [Description]
, CAST(DIMENSION_UNIQUE_NAME AS VARCHAR(255)) AS [Link]
FROM OPENQUERY(CubeLinkedServer,
'SELECT [CATALOG_NAME], [CUBE_NAME]
, [DIMENSION_NAME], [DESCRIPTION]
, [DIMENSION_UNIQUE_NAME]
FROM $SYSTEM.MDSCHEMA_DIMENSIONS
WHERE [DIMENSION_IS_VISIBLE]')
WHERE (CAST([CATALOG_NAME] AS VARCHAR(255))
= @Catalog OR @Catalog IS NULL)
AND (CAST([CUBE_NAME] AS VARCHAR(255))
= @Cube OR @Cube IS NULL)
AND LEFT(CAST(CUBE_NAME AS VARCHAR(255)),1)
<>'$' --Filter out dimensions not in a cube
UNION ALL
--Attributes
SELECT CAST('Attribute' AS VARCHAR(20)) AS [Type]
, CAST(CATALOG_NAME AS VARCHAR(255)) AS [Catalog]
, CAST(CUBE_NAME AS VARCHAR(255)) AS [Cube]
, CAST(LEVEL_CAPTION AS VARCHAR(255)) AS [Name]
, CAST(DESCRIPTION AS VARCHAR(4000)) AS [Description]
, CAST(DIMENSION_UNIQUE_NAME AS VARCHAR(255)) AS [Link]
FROM OPENQUERY(CubeLinkedServer,
'SELECT [CATALOG_NAME], [CUBE_NAME]
, [LEVEL_CAPTION], [DESCRIPTION],
, [DIMENSION_UNIQUE_NAME]
FROM $SYSTEM.MDSCHEMA_LEVELS
WHERE [LEVEL_NUMBER]>0
AND [LEVEL_IS_VISIBLE]')
WHERE (CAST([CATALOG_NAME] AS VARCHAR(255))
= @Catalog OR @Catalog IS NULL)
AND (CAST([CUBE_NAME] AS VARCHAR(255))
= @Cube OR @Cube IS NULL)
AND LEFT(CAST(CUBE_NAME AS VARCHAR(255)),1)
<>'$' --Filter out dimensions not in a cube
UNION ALL
--Measure Groups
SELECT CAST('Measure Group' AS VARCHAR(20)) AS [Type]
, CAST(CATALOG_NAME AS VARCHAR(255)) AS [Catalog]
, CAST(CUBE_NAME AS VARCHAR(255)) AS [Cube]
, CAST(MEASUREGROUP_NAME AS VARCHAR(255)) AS [Name]
, CAST(DESCRIPTION AS VARCHAR(4000)) AS [Description]
, CAST(MEASUREGROUP_NAME AS VARCHAR(255)) AS [Link]
FROM OPENQUERY(CubeLinkedServer,
'SELECT [CATALOG_NAME], [CUBE_NAME]
, [MEASUREGROUP_NAME],
, [DESCRIPTION]
FROM $SYSTEM.MDSCHEMA_MEASUREGROUPS')
WHERE (CAST([CATALOG_NAME] AS VARCHAR(255))
= @Catalog OR @Catalog IS NULL)
AND (CAST([CUBE_NAME] AS VARCHAR(255))
= @Cube OR @Cube IS NULL)
AND LEFT(CAST(CUBE_NAME AS VARCHAR(255)),1)
<>'$' --Filter out dimensions not in a cube
UNION ALL
--Measures
SELECT CAST('Measure' AS VARCHAR(20)) AS [Type]
, CAST(CATALOG_NAME AS VARCHAR(255)) AS [Catalog]
, CAST(CUBE_NAME AS VARCHAR(255)) AS [Cube]
, CAST(MEASURE_NAME AS VARCHAR(255)) AS [Name]
, CAST(DESCRIPTION AS VARCHAR(4000)) AS [Description]
, CAST(MEASUREGROUP_NAME AS VARCHAR(255)) AS [Link]
FROM OPENQUERY(CubeLinkedServer,
'SELECT [CATALOG_NAME], [CUBE_NAME]
, [MEASURE_NAME], [DESCRIPTION],
, [MEASUREGROUP_NAME]
FROM $SYSTEM.MDSCHEMA_MEASURES
WHERE [MEASURE_IS_VISIBLE]')
WHERE (CAST([CATALOG_NAME] AS VARCHAR(255))
= @Catalog OR @Catalog IS NULL)
AND (CAST([CUBE_NAME] AS VARCHAR(255))
= @Cube OR @Cube IS NULL)
AND LEFT(CAST(CUBE_NAME AS VARCHAR(255)),1)
<>'$' --Filter out dimensions not in a cube
)
SELECT *
FROM MetaData
WHERE @Search<>''
AND ([Name] LIKE '%' + @Search + '%'
OR [Description] LIKE '%' + @Search + '%'
)
GO
We can now use these procs to form the basis of a number of SSRS reports which will dynamically query the DMVs to generate the SSAS cube documentation. I’ll be covering this stage in my next post.
- Part 1 – Creating the DMV stored procs
- Part 2 – Create the SSRS reports
- Part 3 – Use spatial data and maps to create a star schema view
- Download Source Code

I specialise in designing and implementing SQL Server business intelligence solutions,
and this is my blog! Just a collection of thoughts, techniques and ramblings on SQL Server, Cubes, Data Warehouses, MDX, DAX and whatever else comes to mind.

This is very interesting stuff. Can’t wait for the other 2 parts of this
Here are this and some other articles on SSAS Dynamic Management Views: http://ssas-wiki.com/w/Articles#DMV_.28Dynamic_Management_View.29
Thanks Sam, some great articles in that list, very useful.
Hi Alex!
A good post, but a little question when specifiying the linked server do you always have to specify the Catalog? Because then it’s not necessary to have that as a parameter is it?
I tried to create a linked server without specifiying the Catalog and it took the first one. While I would imagine that I would get the option to choose the Catalog since it is a part of a parameter.
Any thought about that?
Regards Shakir
Hi Shakir
You’re right that at the moment the catalog parameter doesn’t make that much sense. When I first started this project I intended the catalog to be selectable, however I came across the same problem of the catalog having to be specified in the linked server. I kept the parameter in though for future enhancements. for example you could drop and recreate the linked server dynamically if required.
Alex
hi,
thanks for posting this solution.
I have been searching for a way to track measures from the cube to the source tables they originate from. Your solution only lacks the ability to identify the source table/column and from what I can tell, the system views doesn’t supply this information, but it is possible to accomplish this by querying the solution (.cube) file. Is there a better way to do this?
I don’t think there’s any easy way to do this – without querying the cube file or something similarly complex. There are certainly no DMVs that I’m aware of which provide a lineage of the data source.
If you find a neat way of doing it then please post here – I’d be very interested if you figure it out.
Alex
Hi again
The process is a bit cumbersome, but the required steps can probably be scripted.
There are two files of interest in the solution, the .cube and .partitions files.
So far, I have only investigated the .cube file.
Get latest cube definition file (.cube) from source control and store its contents as XML type in the database.
I created a table, dbo.Cube, in which I store the cube definition as XML.
Then I run the query below to get the desired information. Combined with the DMV queries you have provided, it’s just what I need.
;WITH XMLNAMESPACES( — only one namespace was required for my queries
‘xmlns=”http://schemas.microsoft.com/analysisservices/2003/engine”‘ AS A
, DEFAULT ‘http://schemas.microsoft.com/analysisservices/2003/engine’
)
SELECT
x.m.value(‘(ID)[1]‘, ‘varchar(64)’) AS ID
,x.m.value(‘(Name)[1]‘, ‘varchar(64)’) AS Name
,y.n.value(‘(ID)[1]‘, ‘varchar(64)’) AS MeasureID
,y.n.value(‘(Name)[1]‘, ‘varchar(64)’) AS MeasureName
,y.n.value(‘(DataType)[1]‘, ‘varchar(64)’) AS MeasureDataType
,y.n.value(‘(Source/DataType)[1]‘, ‘varchar(64)’) AS MeasureSourceDataType
,y.n.value(‘(Source/Source/TableID)[1]‘, ‘varchar(64)’) AS SourceTableID
,y.n.value(‘(Source/Source/ColumnID)[1]‘, ‘varchar(64)’) AS SourceColumnID
,x.m.value(‘(../../Name)[1]‘, ‘varchar(64)’) AS Cube
FROM (SELECT Definition FROM DBO.Cube) AS P
CROSS APPLY Definition.nodes(‘/Cube/MeasureGroups/MeasureGroup’) x(m)
CROSS APPLY Definition.nodes(‘/Cube/MeasureGroups/MeasureGroup/Measures/Measure’) y(n)
WHERE x.m.value(‘(ID)[1]‘, ‘varchar(64)’)=y.n.value(‘(../../ID)[1]‘, ‘varchar(64)’)
Good work! I’ll take a more detailed look when I get a few minutes spare.
Thanks for sharing
I discovered within the $system DMVs the relational source of the multidimensional data.
The MDSCHEMA_PROPERTIES rowset contains Information about the relational source, specifically the column PROPERTY_ATTRIBUTE_HIERARCHY_NAME. The discription within BOL is ‘The name of the attribute hierarchy sourcing this property.’
Maybe you guys can check it out and let me know whether this is it. Also could you give me a heads up as to what PROPERTY_CARDINALITY means?
Thanks.
See here :
http://msdn.microsoft.com/en-us/library/ms126309.aspx
I can’t find any relational source field details in that DMV? The PROPERTY_ATTRIBUTE_HIERARCHY_NAME just shows which dimension attribute is used in the selected hierarchy, not where it comes from in the underlying source database.
PROPERTY_CARDINALITY is an interesting one. BOL states that it’s the “The cardinality of the property”, which is less than helpful. From a quick check of a few cubes, it seems to represent the grouping behavior of the attribute; encourage (MANY) or discourage (ONE).
If anyone has any further details on this, please speak up!
Alex