I'm doing some exploratory work with tiny test dimensions and cubes. I'm hoping to finally fully understand SSAS's concept of a "dimension attribute", which I find pretty incomprehensible, though I've used SSAS for years without really getting to the bottom of it.
But that's too broad a question. My problem now is this:
I've created an Employee dimension. Key column is EID (int), Name column is Name (varchar). OK, my naming conventions aren't brilliant (but good naming conventions seem to be very difficult in SSAS dimension design, given the fact that all object names are exposed to users).
There is also an attribute called Salary.
What I'm trying to do here is explore the possibility of a "dimension leaf-level property". Not really "dimension attributes" in the sense SSAS uses them, though the only way to implement them is as dimension attributes. What I mean by a "leaf-level property" is a non-aggregatable "attribute", with the same cardinality as the leaf level (or, in any case, to be treated as having the same cardinality). I don't want to aggregate by Salary, for the purposes of this exercise: I just want Salary to be available as a property of each leaf-level member of the dimension. A bit like an extension of the Key Column and Name Column properties.
I'm familiar with this common way of showing member properties:
WITH MEMBER Measures.ESal AS Employee.EID.CurrentMember.Properties("Salary")
SELECT
Measures.ESal ON 0,
Employee.EID.EID.Members
ON 1
FROM $Employee
This works. To prove that I'm only returning members from the leaf level, here's the result set:
(It makes sense that a member property for a non-leaf level might not have a value - and I've read that in this case, MDX simply throw an error rather than showing values for the leaf-level members and nothing for non-leaf).
But trying to use DIMENSION PROPERTIES causes an error:
SELECT
{} ON 0,
Employee.EID.EID.Members
DIMENSION PROPERTIES Employee.Salary
ON 1
FROM $Employee
Result: Query (4, 22) The [Employee].[Salary] dimension attribute was not found.
If I put the hierarchy and level in, though, it works (though SSMS doesn't actually show anything specified in DIMENSION PROPERTIES; as I'd heard already):
SELECT
{} ON 0,
Employee.EID.EID.Members
DIMENSION PROPERTIES Employee.EID.EID.Salary
ON 1
FROM $Employee
Result: just like before, but with no ESal column (obviously).
Two questions:
Why does the Salary attribute have to be addressed as an attribute
of dimension/hierarchy/level Employee.EID.EID? Surely it's an
attribute in the dimension? (I find the way SSAS/SSDT implements
multiple hierarchies deeply confused and confusing)
What is the point of DIMENSION PROPERTIES? Do other clients
actually show what it returns? If so, isn't it then a nightmare to
test this code?
Related
For the life of me I cannot figure out why MDX defines dimensionality per-attribute on a dimension rather than on the key. Perhaps I'm misunderstanding something here, but it seems like a very odd way to do this if I'm understanding things correctly. Let's say I have the following data:
Person
ID (Key)
Name
Age
And I have some data like this: [('Tom123', 'Tom', 15), ('Brad456', 'Brad', 16).
Now, why I could select the two users the following two ways:
{Person.Name.Tom, Person.Name.Brad}
Or:
{Person.ID.Tom123, Person.ID.Brad456}
But not the following way:
{Person.Name.Tom, Person.ID.Brad456}
Yet all three use the same 'dimension' and even 'dimensionality' since all three ways uniquely address the same two Person entities!
This seems so odd to me, in that they are both using the same 'dimension' and 'dimensionality' and should be able to use the Key for that dimension rather than thinking each attribute is unique. Why is this so? Or, am I misunderstanding something in this.
If we use this image:
Why would it matter if we address the individual cube (tuple) by doing: {Product.TV, Geography.Asia, Time.Q1} or doing {Product.TV, Geography.Asia, Time.Quarter One}. They're just two ways of doing exactly the same thing but yet MDX considers them different dimensionality (?).
That is an excellect question.
Yet all three use the same 'dimension' and even 'dimensionality' since
all three ways uniquely address the same two Person entities!
This seems so odd to me, in that they are both using the same
'dimension' and 'dimensionality' and should be able to use the Key for
that dimension rather than thinking each attribute is unique. Why is
this so? Or, am I misunderstanding something in this.
So for any language, the syntax is checked before anything else. The case you are refering is the only instance where Dimensionality can be ignored. But it will not be wise for a language to go evaluate the data first(in terms of SSAS and MDX its called AttributeID). Secondly this will be more confusing to a user. building on your example
{Person.Name.Tom, Person.ID.Brad456}
lets we have 100 people in Newyork, so as per your logic the following
the set will be {Person.City.Newyork}, then MDX will replace all 100 IDs. This would prevent MDX from using Aggregates, which is the biggest advantge of a CUBE. Mostly the queries sent to a Cube are targeted towards summarized data. Most queries in MDX would need data of entire NEWYORK rather then a single person in NEWYORK
So to summarize, the compile time will increase and the Aggregates will not be useable.
can someone definitively tell me why
[Dimension].[Hierarchy].[Level].&[(Unknown)] doesn't make sense
while
[Dimension].[Hierarchy].[Level].&[some_other_member] does
and yet both [Dimension].[Hierarchy].&[(Unknown)] and [Dimension].[Hierarchy].&[some_other_member]
both do
To me isn't unknown simply the case where the data doesn't fall into a defined hierarchy member?
this area of SSAS seems a bit opaque to me.
Any link to the official definition would be great.
Each member is at one level of a hierarchy. If you have a standard attribute hierarchy, then you have two levels: The All level containing the All member and the level named like the hierarchy, which contains all the members found in the attribute column of the relational dimension table as well as the Unknown member. The latter is contained on that level, as it is clearly not part of the All level, and it is included in the sum of all members of its level to give the numbers for the All member.
The official documentation of the UnknownMember function describes what I described above and some special cases like the case that an attribute hierarchy has set the IsAggregatable property to false (i. e. the All level is missing, an the level named like the attribute is to only one, end hence the top level).
I have a dimension ItemSales with a hierarchy of levels like Site->ItemType->Item
ItemType is not unique. Sites can sell the same ItemType.
I want to exclude a certain type from the totals (such as Unknown)
This must be easy but I'm stuck. It seems like Except would work but as far I can work out, except requires me to enumerate every site
Except([ItemSales].[Sites].[ItemType].Members],{[ItemSales].[site1].[unknown],[ItemSales].[site2].[Unknown]})
this also doesn't help if I just want to aggregate at Sites level.
The examples I see for filter focus on numerical filters for measures. Can you filter on the name of a member or whatever we call the key value it gets from the column?
Sorry for asking such an easy question but I'm not getting any less confused the more I read.
Not sure this is the best way to address your problem, but you can do something with the Filter() function using the .name of the members to keep all [ItemType] that are not 'Unknown' :
Filter(
[ItemSales].[Sites].[ItemType].Members,
[ItemSales].[Sites].currentMember.name <> 'Unknown'
)
I'm using SQL Server Analysis Services.
I have a calculated member that, for now, just does this:
[MyDimension].[MyOnlyHierarchy].CurrentMember.Properties("MEMBER_UNIQUE_NAME")
Previously, I had just written [MyDimension].[MyOnlyHierarchy].CurrentMember.UniqueName. They should be the same anyway.
Now, I used SQL Profiler to get ahold of the query my application issues. For a simple calculated member in [MyDimension].[MyOnlyHierarchy] that just sums to different members, say with IDs 401 and 402, I get this result:
[MyDimension].[MyOnlyHierarchy].&[401][MyDimension].[MyOnlyHierarchy].&[402]
In other words, it is as if AS evaluates the underlying members and concatenates the results, rather than giving me the unique name of the calculated member...
The REALLY strange thing to me is that when I take the original query, and prepend the following:
WITH MEMBER [Measures].[GiveMeCalculatedMemberUniqueName]
AS
(
[MyDimension].[MyOnlyHierarchy].CurrentMember.Properties("MEMBER_UNIQUE_NAME")
)
...rest of query
I get the CORRECT results using this second measure! The context is the same (to me at least). Everything is the same... Yet the measure declared in the project file gives a different result than this inline calculated member.
What's going on here? Note, I've redeployed 10000 times, and I've checked the actual definition in the cube on the server and everything. It just doesn't make sense to me.
Calculations are evaluated based on solve order. may be because you moved it down and it was how the solve order was supposed to work it gives you correct result . I have a little blog on solve order here but there are many more articles on internet.
HTH
Funny... I've been sitting for about 2-3 hours with this, exploring every thought; then, after I post this question I decide to try one more thing:
move the calulated member definition to the bottom of the calculated members script file in the project.
This now gives the correct result.
I am fairly new to nHibernate and DDD, so please bear with me.
I have a requirement to create a new report from my SQL table. The report is read-only and will be bound to a GridView control in an ASP.NET application.
The report contains the following fields Style, Color, Size, LAQty, MTLQty, Status.
I have the entities for Style, Color and Size, which I use in other asp.net pages. I use them via repositories. I am not sure If should use the same entities for my report or not. If I use them, where I am supposed to map the Qty and Status fields?
If I should not use the same entities, should I create a new class for the report?
As said I am new to this and just trying to learn and code properly.
Thank you
For reports its usually easier to use plain values or special DTO's. Of course you can query for the entity that references all the information, but to put it into the list (eg. using databinding) it's handier to have a single class that contains all the values plain.
To get more specific solutions as the few bellow you need to tell us a little about your domain model. How does the class model look like?
generally, you have at least three options to get "plain" values form the database using NHibernate.
Write HQL that returns an array of values
For instance:
select e1.Style, e1.Color, e1.Size, e2.LAQty, e2.MTLQty
from entity1 inner join entity2
where (some condition)
the result will be a list of object[]. Every item in the list is a row, every item in the object[] is a column. This is quite like sql, but on a higher level (you describe the query on entity level) and is database independent.
Or you create a DTO (data transfer object) only to hold one row of the result:
select new ReportDto(e1.Style, e1.Color, e1.Size, e2.LAQty, e2.MTLQty)
from entity1 inner join entity2
where (some condition)
ReportDto need to implement a constructor that has all this arguments. The result is a list of ReportDto.
Or you use CriteriaAPI (recommended)
session.CreateCriteria(typeof(Entity1), "e1")
.CreateCriteria(typeof(Entity2), "e2")
.Add( /* some condition */ )
.Add(Projections.Property("e1.Style", "Style"))
.Add(Projections.Property("e1.Color", "Color"))
.Add(Projections.Property("e1.Size", "Size"))
.Add(Projections.Property("e2.LAQty", "LAQty"))
.Add(Projections.Property("e2.MTLQty", "MTLQty"))
.SetResultTransformer(AliasToBean(typeof(ReportDto)))
.List<ReportDto>();
The ReportDto needs to have a proeprty with the name of each alias "Style", "Color" etc. The output is a list of ReportDto.
I'm not schooled in DDD exactly, but I've always modeled my nouns as types and I'm surprised the report itself is an entity. DDD or not, I wouldn't do that, rather I'd have my reports reflect the results of a query, in which quantity is presumably count(*) or sum(lineItem.quantity) and status is also calculated (perhaps, in the page).
You haven't described your domain, but there is a clue on those column headings that you may be doing a pivot over the data to create LAQty, MTLQty which you'll find hard to do in nHibernate as its designed for OLTP and does not even do UNION last I checked. That said, there is nothing wrong with abusing HQL (Hibernate Query Language) for doing lightweight reporting, as long as you understand you are abusing it.
I see Stefan has done a grand job of describing the syntax for that, so I'll stop there :-)