Showing posts with label group. Show all posts
Showing posts with label group. Show all posts

Wednesday, March 28, 2012

Incorrect Totals

Here's my cube structure in a nutshell.

I've got a measure group called MG1 which contains measure "Units". I've got another measure group called MG2 which contains measure "Price".

I want to add a new measure called "Value" that should correspond to Units * Price.

I'm trying to use MDX script to do this calculation:

[Measures].[Value] = [Measures].[Units] * [Measures].[Price]

This seems to produce the right results at leaves level, but when i check the Totals in the Cube Browser they are incorrect because in the totals calculation Prices are summed up and multiplied by the sum of Units. The Totals should instead be calculated by doing a sum of all the leaves Values if you see what i mean.

Is there anything obvious i'm missing here?

To try and explain further, here're the (wrong) results i'm getting:

Units Price Value
Product A -27,880 0.00570 -158.92
Product B -11,845 0.00560 -66.33
Total -39,725 0.01130 -448.89

And here're the results i would like to get:

Units Price Value
Product A -27,880 0.00570 -158.92
Product B -11,845 0.00560 -66.33
Total -39,725 0.01130 -225.25

As you can see from above the problem is to do with the way Value is calculated for Total.

Any suggestion on how i could achieve the desired results through MDX script and/or changes in cube design ?

|||

Do you have the option of moving Price to a dimension? This is often how price is recorded if it is describing something like a product.

Barring this, I would recommend calculating Units * Price in your DSV and then simply recording it in a new measure in your MG1 measure group using an additive function.

Good luck,
Bryan

|||

Price is in measure group MG2 because it also depends on the value of another dimension "Catalog". The Catalog dimension is not directly linked to MG1. So depending on which catalog is chosen we have different prices accross products. So i really would need to keep Units and Price in 2 separate fact tables (measure groups) to avoid having a huge single fact table with all combinations.

I think what i'm trying to achieve is fairly simple, ie. the only issue is to do with Totals. But maybe i'm missing something.

I would really need to get this working through MDX script because i will need to use the "Value" measure inside other calculated measures so i cannot even use a Measure Expression, i think.

|||

So, if a product can have multiple prices depending on the catalog you have to know the catalog used in the purchase. In that case, does MG1 also have a direct relationship with the Catalog dimension?

Alternatively, can this be resolved in the DSV? Could you create a named calculation in the DSV that multiplies the units by price to give you a transaction total? The total seems to be additive. This might be an easier solutoin for you.


Bryan

|||

This seems like a good scenario for "measure expressions" - if you inspect the Adventure Works cube, various Sales Amount measures are multiplied by currency rates. For example, you could create a new "sum" measure like [Value] on the MG1 "Units" field. Then, for this new measure, configure the "Measure Expression" property as:

[Measures].[Value] * [Measures].[Price]

This entry in Chris Webb's blog discusses measure expressions:

...

But here's a cool cube design feature that doesn't cause any conflict of interest for me - measure expessions. The easiest way to explain what they are is to explain one scenario where they're useful. In AS2K, if you've tried to model currency conversion, you're probably aware that you need to multiply the measure values in your main fact table by the currency rate before any aggregation of the resulting values takes place. You then have two choices for your cube: either precalculate the values in the fact table itself or in a view, which leads to much faster queries but also much bigger cubes, and which means the rates can't then be altered without reprocessing; or do the currency conversion at runtime using MDX, which generally leads to slower queries but which allows users to change the currency rates dynamically (for example using writeback). Neither of these options are exactly ideal so in AS2005 measure expressions offer a kind of halfway house - they are calculated at query time and yet are much faster than the equivalent MDX, but the price you pay is that they are nowhere near as flexible as calculated members in terms of the calculations you can define.

...

|||I could not get the cube calculations correct with the 2 Fact tables as described above. So I've finally opted for 1 Fact table with all the "combinations": CatalogID, ProductID, Units, ProductPriceForCatalog, Value, etc. This means that Value is calculated as part of my SSIS package which updates the Fact table with new entries every day, so this calculation is not performed in the cube via MDX script any more. The downside of this solution is that my Fact table will contain many more rows...

Incorrect Totals

Here's my cube structure in a nutshell.

I've got a measure group called MG1 which contains measure "Units". I've got another measure group called MG2 which contains measure "Price".

I want to add a new measure called "Value" that should correspond to Units * Price.

I'm trying to use MDX script to do this calculation:

[Measures].[Value] = [Measures].[Units] * [Measures].[Price]

This seems to produce the right results at leaves level, but when i check the Totals in the Cube Browser they are incorrect because in the totals calculation Prices are summed up and multiplied by the sum of Units. The Totals should instead be calculated by doing a sum of all the leaves Values if you see what i mean.

Is there anything obvious i'm missing here?

To try and explain further, here're the (wrong) results i'm getting:

Units Price Value
Product A -27,880 0.00570 -158.92
Product B -11,845 0.00560 -66.33
Total -39,725 0.01130 -448.89

And here're the results i would like to get:

Units Price Value
Product A -27,880 0.00570 -158.92
Product B -11,845 0.00560 -66.33
Total -39,725 0.01130 -225.25

As you can see from above the problem is to do with the way Value is calculated for Total.

Any suggestion on how i could achieve the desired results through MDX script and/or changes in cube design ?

|||

Do you have the option of moving Price to a dimension? This is often how price is recorded if it is describing something like a product.

Barring this, I would recommend calculating Units * Price in your DSV and then simply recording it in a new measure in your MG1 measure group using an additive function.

Good luck,
Bryan

|||

Price is in measure group MG2 because it also depends on the value of another dimension "Catalog". The Catalog dimension is not directly linked to MG1. So depending on which catalog is chosen we have different prices accross products. So i really would need to keep Units and Price in 2 separate fact tables (measure groups) to avoid having a huge single fact table with all combinations.

I think what i'm trying to achieve is fairly simple, ie. the only issue is to do with Totals. But maybe i'm missing something.

I would really need to get this working through MDX script because i will need to use the "Value" measure inside other calculated measures so i cannot even use a Measure Expression, i think.

|||

So, if a product can have multiple prices depending on the catalog you have to know the catalog used in the purchase. In that case, does MG1 also have a direct relationship with the Catalog dimension?

Alternatively, can this be resolved in the DSV? Could you create a named calculation in the DSV that multiplies the units by price to give you a transaction total? The total seems to be additive. This might be an easier solutoin for you.


Bryan

|||

This seems like a good scenario for "measure expressions" - if you inspect the Adventure Works cube, various Sales Amount measures are multiplied by currency rates. For example, you could create a new "sum" measure like [Value] on the MG1 "Units" field. Then, for this new measure, configure the "Measure Expression" property as:

[Measures].[Value] * [Measures].[Price]

This entry in Chris Webb's blog discusses measure expressions:

...

But here's a cool cube design feature that doesn't cause any conflict of interest for me - measure expessions. The easiest way to explain what they are is to explain one scenario where they're useful. In AS2K, if you've tried to model currency conversion, you're probably aware that you need to multiply the measure values in your main fact table by the currency rate before any aggregation of the resulting values takes place. You then have two choices for your cube: either precalculate the values in the fact table itself or in a view, which leads to much faster queries but also much bigger cubes, and which means the rates can't then be altered without reprocessing; or do the currency conversion at runtime using MDX, which generally leads to slower queries but which allows users to change the currency rates dynamically (for example using writeback). Neither of these options are exactly ideal so in AS2005 measure expressions offer a kind of halfway house - they are calculated at query time and yet are much faster than the equivalent MDX, but the price you pay is that they are nowhere near as flexible as calculated members in terms of the calculations you can define.

...

|||I could not get the cube calculations correct with the 2 Fact tables as described above. So I've finally opted for 1 Fact table with all the "combinations": CatalogID, ProductID, Units, ProductPriceForCatalog, Value, etc. This means that Value is calculated as part of my SSIS package which updates the Fact table with new entries every day, so this calculation is not performed in the cube via MDX script any more. The downside of this solution is that my Fact table will contain many more rows...

Monday, March 26, 2012

Incorrect syntax near the keyword Declare.

Dear Group,

I am trying to create a view and keep getting the Incorrect syntax near the
keyword 'Declare'" error.

Here is the code I am writing.

Create view fixed_airs (sid, fad_a2, fad_a3) as
Declare @.sid int,
@.fad_a2 int,
@.fad_a3 int
select @.sid=cast(substring(subject_id,1,8)as int) ,
@.fad_a2 =cast (substring(fad_2_4,1,1) as int),
@.fad_a3=cast(substring(fad_2_4,2,1) as int)
from parentpacket.

Thanks for the help in advance.

Jeff MagouirkJeff Magouirk wrote:
> Dear Group,
> I am trying to create a view and keep getting the Incorrect syntax near the
> keyword 'Declare'" error.
> Here is the code I am writing.
> Create view fixed_airs (sid, fad_a2, fad_a3) as
> Declare @.sid int,
> @.fad_a2 int,
> @.fad_a3 int
> select @.sid=cast(substring(subject_id,1,8)as int) ,
> @.fad_a2 =cast (substring(fad_2_4,1,1) as int),
> @.fad_a3=cast(substring(fad_2_4,2,1) as int)
> from parentpacket.
> Thanks for the help in advance.
> Jeff Magouirk

You keep getting syntax errors because you're using illegal syntax in
your CREATE VIEW statement. :D You can't use DECLARE, nor can you pass
in variables to a view. Check Books Online for proper syntax. But, in a
nutshell, you can only use a SELECT statement in a view.

Zachsql

Monday, March 19, 2012

Incorrect group sum problem

Hi all,
I have encountered a very strange problem in RS2005. In my report I
show real estate transactions. When I have more than one record with
the same TR_ID (transaction id) I need to popolate nulls into certain
money fields like AGC_amt and some other fields. These amounts are the
same in all transactions with the same TR_ID and should be treated as
one value not a repeating value. Let's say $1,000 in AGC_amt should
remain $1,000 even for every transaction with the same TR_ID it
repeats. I conditionally place nulls into those texboxes that have the
same TR_ID in the previous record so only the first record has the
value.
=iif(Fields!TR_id.Value = Previous(Fields!TR_id.Value), nothing,
Fields!AGC_amt.Value)
I need to sum up all these values in my group footer. What I have in my
report is the amount equal to total as if I did not place nulls! It is
easy to show in example:
tr_id AGC_am
----
12345 $1,000
same tr_id I place null here although it is $1,000 in dataset
same tr_id also null for the same reason
group sum: $3,000 (instead of $1,000 what I expect!)
formula for the sum in group footer:
=Sum(Fields!AGC_amt.Value)
What is wrong here? I tried to place zeros in place of nulls and get
the same incorrect number, i.e. I have $1,000, $0 and $0 totaling to
$3,000 in group footer!!!
I am going insane!
Please, help!
Thanks,
StanNever mind, everyone! My mistake. There was another field in my dataset
I was supposed to use in my group totals. I just did not know about it.
Stan
suslikovich wrote:
> Hi all,
> I have encountered a very strange problem in RS2005. In my report I
> show real estate transactions. When I have more than one record with
> the same TR_ID (transaction id) I need to popolate nulls into certain
> money fields like AGC_amt and some other fields. These amounts are the
> same in all transactions with the same TR_ID and should be treated as
> one value not a repeating value. Let's say $1,000 in AGC_amt should
> remain $1,000 even for every transaction with the same TR_ID it
> repeats. I conditionally place nulls into those texboxes that have the
> same TR_ID in the previous record so only the first record has the
> value.
> =iif(Fields!TR_id.Value = Previous(Fields!TR_id.Value), nothing,
> Fields!AGC_amt.Value)
> I need to sum up all these values in my group footer. What I have in my
> report is the amount equal to total as if I did not place nulls! It is
> easy to show in example:
> tr_id AGC_am
> ----
> 12345 $1,000
> same tr_id I place null here although it is $1,000 in dataset
> same tr_id also null for the same reason
> group sum: $3,000 (instead of $1,000 what I expect!)
> formula for the sum in group footer:
> =Sum(Fields!AGC_amt.Value)
> What is wrong here? I tried to place zeros in place of nulls and get
> the same incorrect number, i.e. I have $1,000, $0 and $0 totaling to
> $3,000 in group footer!!!
> I am going insane!
> Please, help!
> Thanks,
> Stan

Friday, March 9, 2012

Inconsistency in HTML display

Hi all i am currently using a custom aggregate function in the Stored Proc to Concatenate certain fields and group the others. The concatenation is done be leaving an empty line (Line Break) inbetween. The problem is that the New Line Break is getting displayed in the PDF format of the Reports generated using Reporting Service 2005 but in the HTML (using IE) format the Line break does not occur, can anyone help me out with this. Doesnt IE support New Line?

You can change the width of this line with specific property (lineheigt) on that TABLEROW object. You must complete the "write" expression on that property and the results are fine.

For example you can use the function posted below to get the number of occurence of char(13) character.

TABLEROW1.LineHeight= n*(1-occurs(@.yourstring,char(13))

Create function occurs

(

@.iStr varchar(4000),

@.fStr varchar(100)

)

Returns smallint As

Begin

Declare @.rStr varchar(100)

Select @.rStr = case when charindex(left(@.fStr,1),@.fStr,2)>0 then stuff(@.fStr,charindex(left(@.fStr,1),@.fStr,2),0,'~') else Replicate('~',datalength(@.fStr)+1) end

Return(datalength(Replace(Replace(@.iStr,@.fStr,@.rStr),@.fStr,@.rStr)) - datalength(@.iStr))

End

Friday, February 24, 2012

Include ID field in GROUP BY statement

I've got a query where i need to return a max value based on a select but one of the fields i need to return in the results is the records primary key ID No. This messes up the MAX bit and means that all results are returned, not just the max one.

The query i'm using is very long so i've simplified what i mean by the example below. Say i have a table 'Fruits':

ID FruitName Cost
1 Apple 0.45
2 Apple 0.63
3 Apple 0.52
4 Pear 0.89
5 Pear 0.83

And run the query:

select max(Cost),FruitName From Fruits
group by FruitName

It'll correctly return:

FruitName Cost
Apple 0.63
Pear 0.89

Now i need the ID also returned by my query so i go:

select max(Cost),FruitName,ID From Fruits
group by FruitName,ID

This doesnt return the above results with the ID appended to it, it instead returns:

ID FruitName Cost
1 Apple 0.45
2 Apple 0.63
3 Apple 0.52
4 Pear 0.89
5 Pear 0.83

As the ID is always distinct and therefore messes up the grouping. How in this instance would i return the correct result of:

ID FruitName Cost
2 Apple 0.63
4 Pear 0.89

Thanks.

I don't think you can do that with the ID field because there are multiple Ids for each item while using the group by. Can you use a Having clause? ie

select Cost,FruitName From Fruits
group by FruitName
having max(Cost)

This is a shot in the dark as i did not actually try your data. Hope it works though :)

|||

Thanks but dont think that would work as the 'HAVING' as i see it is just used to filter the results of the query so you'd use it if for example you wanted to only show max fuit more than £0.10

select Cost,FruitName From Fruit
group by FruitName,Cost
having max(Cost) > 0.1

Thats how i see it (could be wrong). But it still doesnt handle the problem of the ID.

|||

Hi,

This is a round about way, but it works

Select

FruitName,cost,(Select IDfrom Fruits fWhere f.Cost=frt.cost)as IDfrom

(

select FruitName,max(cost)as costFrom Fruits

group

by FruitName) frt|||

Hi TheGrox,

The below query may help you.

select id,fruitname,costfrom (select row_number()over (partitionby fruitnameorder by costdesc)as rownum,id,fruitname,costfrom Fruits) Fwhere rownum = 1

The main trick here is using the ROW_NUMBER() OVER (PARTITION BY...) clause

This is very like getting top n records from a table belonging to each category. You can follow the article athttp://www.kodyaz.com/articles/top-n-random-rows-foreach-category-or-group.aspx for more details and a sample for ROW_NUMBER() OVER (PARTITION BY...)

Eralper

http://www.kodyaz.com

|||

If you are using SQL 2000 you can try this:

Select t1.FruitName,t2.cost, Idfrom Fruits t1join (select FruitName,max(cost)as costFrom Fruitsgroup by FruitName ) t2on t1.FruitName = t2.fruitnameand t1.Cost = t2.cost

|||

Here is another one:

select t1.*from fruitsas t1where t1.ID= (select top 1 t2.IDfrom fruitsas t2where t2.FruitName = t1.FruitNameorder by t2.costDESC)
|||

Limno

I like your query better than mine. I am joining on name and cost. If there are multiple records with same name and costs, the join could return multiple records for same "Fruit" which might be incorrect.

|||I learned that solution from Umachandar Jayachandran. He is super.

Inadequate Results When Using Group By On Subqueries With Newid()

/*
RUN THIS QUERY AT LEAST 10 TIMES - YOU WILL BE IN A SURPRISE
DON'T BE AFFRAID - 1 SEC FOR EACH RUN
*/
/*
This query should generate 1 milion of mixed random ones and zeroes,
and group their counts
*/
select X,"Count"=count(*) from
(
select X=case when checksum(newid())>0 then 0 else 1 end
from ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX1
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX2
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX3
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX4
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX5
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX6
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX7
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX8
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX9
) XXX group by X

/*
RESULTS:

Correct - count can vary
| Count | X |
-----
| 524288 | 1 |
-----
| 524288 | 0 |
-----

But you can also get this result
| Count | X |
-----
| 786432 | 1 | <-- 1 !!!
-----
| 262144 | 1 | <-- 1 !!!
-----

!!!!!!!!!!! BIFURCATE ONE !!!!!!!!!!!!!!!
*/

--And this query is seems to be correct (not so fast, about 2 min to get output)
declare @.t table (X int)
insert @.t(X)
select X=case when checksum(newid())>0 then 0 else 1 end
from ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX1
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX2
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX3
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX4
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX5
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX6
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX7
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX8
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX9
select X,"Count"=count(*) from @.t
group by X

/*
This query is simillar, but it's principle is different, because if error during query occurs,
@.table would disappear and #table not. However MSSQLSERVER2K implementation prefers physical #tables ;], that's why this query lasts about 20 sec. Result is also correct.
*/
create table #t (X int)
insert #t(X)
select X=case when checksum(newid())>0 then 0 else 1 end
from ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX1
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX2
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX3
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX4
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX5
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX6
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX7
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX8
cross join ( select 1 as X union all select 1 union all select 1 union all select 1 ) XXX9
select X,"Count"=count(*) from #t
group by X
drop table #t

/*
Syntax "CHECKSUM(NEWID())" gives fast pseudo-random int for each usage ( not like RAND() - once per query and seed )
Problem is not bind to CHECKSUM(), but "NEWID()" AND "GROUP BY" combination.
MS SQL Server 2000 has built-in strange "select-driven" ordering routine, group by uses ordering ...?
*/

/*
Tested on Microsoft SQL Server 2000 SP2 - many different hardware
*/Check out the following article:

article (http://support.microsoft.com/default.aspx?scid=KB;en-us;293219&)|||Originally posted by rnealejr
Check out the following article:

article (http://support.microsoft.com/default.aspx?scid=KB;en-us;293219&)

This patch is unofficial and not available to public. I would cripple my SQL server grudgingly. My query is also not corellated as this Microsoft article says. Did you try my query on server with this patch applied with correct results?|||It is available to the general public - you just have to contact them. I agree though that the remarks by ms in the article are not reassuring but that is your decision. I have had to apply these type of intermediate fixes before and have had no problems (from my experiences with these fixes, you can back them out if necessary - but you can confirm that with ms).

To apply any release to your production system from ms without testing it first would be asking for disaster. If you wanted to pursue this, I am sure that you have sql server running on your desktop that has the same issue - just apply the fix to that and see.