Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 ROLLUP with GROUP BY and Categories

Author  Topic 

rythm123us
Starting Member

27 Posts

Posted - 2005-09-11 : 22:40:21
I am trying to display Hieracrhial Data. I am running into trouble when I try to display a PRODUCT multiple times when it has different PRICE.

Please read below to see what I mean:

tbl_Category:
CategoryID ParentID Category Lineage SortOrder
1 0 All 1 0
2 1 Beer 1.1 1
3 2 Domestic 1.1.1 2
37 1 Wine 1.4 38
38 37 Domestic 1.4.1 39
39 38 California 1.4.1.1 40


tbl_Sales:
SalesID ProductID Quantity Price Cost
20935 1554 1 6.99 4.91
20935 721 1 10.99 8
20934 786 1 9.99 7.35
20934 786 2 9.99 7.35
20933 1554 1 6.99 4.91
20933 1554 1 5.99 4.91


tbl_Products:
ProductID Product CategoryID
1554 Woodbridge Chardonnay, 750 ml 39
721 SHARPE HILL RED SERAPH, 750 ml 38
786 BUD , 12 oz 12 pack Bottle(s) 3


The Result I would like to see
SalesID CategoryID ParentID CategoryText Lineage SortOrder Quantity Price Cost
20935 1 0 All 1 0 2 17.98 12.91
20935 37 1 Wine 1.4 3800 2 17.98 12.91
20935 38 37 Domestic 1.4.1 3900 2 17.98 12.91
20935 -1 38 SHARPE HILL RED SERAPH, 750 ml X.1.4.1 3901 1 10.99 8
20935 39 38 California 1.4.1.1 4000 1 6.99 4.91
20935 -1 39 Woodbridge Chardonnay, 750 ml X.1.4.1.1 4001 1 6.99 4.91
20934 1 0 All 1 0 3 29.97 22.05
20934 2 1 Beer 1.1 100 3 29.97 22.05
20934 3 2 Domestic 1.1.1 200 3 29.97 22.05
20934 -1 3 BUD , 12 oz 12 pack Bottle(s) X.1.1.1 201 3 29.97 22.05
20933 1 0 All 1 0 2 12.98 9.82
20933 37 1 Wine 1.4 3800 2 12.98 9.82
20933 38 37 Domestic 1.4.1 3900 2 12.98 9.82
20933 39 38 California 1.4.1.1 4000 2 12.98 9.82
20933 -1 39 Woodbridge Chardonnay, 750 ml X.1.4.1.1 4001 1 6.99 4.91
20933 -1 39 Woodbridge Chardonnay, 750 ml X.1.4.1.1 4001 1 5.99 4.91



What I get is:
SalesID CategoryID ParentID CategoryText Lineage SortOrder Quantity Price Cost
20935 1 0 All 1 0 1 6.99 4.91
20935 1 0 All 1 0 1 10.99 8
20935 37 1 Wine 1.4 3800 1 6.99 4.91
20935 37 1 Wine 1.4 3800 1 10.99 8
20935 38 37 Domestic 1.4.1 3900 1 6.99 4.91
20935 38 37 Domestic 1.4.1 3900 1 10.99 8
20935 -1 38 SHARPE HILL RED SERAPH, 750 ml X.1.4.1 3901 1 10.99 8
20935 39 38 California 1.4.1.1 4000 1 6.99 4.91
20935 -1 39 Woodbridge Chardonnay, 750 ml X.1.4.1.1 4001 1 6.99 4.91
20934 1 0 All 1 0 3 19.98 14.7
20934 2 1 Beer 1.1 100 3 19.98 14.7
20934 3 2 Domestic 1.1.1 200 3 19.98 14.7
20934 -1 3 BUD , 12 oz 12 pack Bottle(s) X.1.1.1 201 3 19.98 14.7
20933 1 0 All 1 0 2 12.98 9.82
20933 37 1 Wine 1.4 3800 2 12.98 9.82
20933 38 37 Domestic 1.4.1 3900 2 12.98 9.82
20933 39 38 California 1.4.1.1 4000 2 12.98 9.82
20933 -1 39 Woodbridge Chardonnay, 750 ml X.1.4.1.1 4001 1 5.99 4.91
20933 -1 39 Woodbridge Chardonnay, 750 ml X.1.4.1.1 4001 1 6.99 4.91


The Query:
DECLARE
@start smalldatetime,
@end smalldatetime;

SET @start = '9/10/05'
SET @end = '9/11/05'


SELECT *
FROM
(
SELECT
A.SalesID,
CASE WHEN (A.GRP = 1)
THEN C.CategoryID
ELSE -1
END AS CategoryID,
CASE WHEN (A.GRP = 1)
THEN C.ParentID
ELSE Max(A.ParentID)
END AS ParentID,
CASE WHEN (A.GRP = 1)
THEN C.CategoryText
ELSE A.Product
END AS CategoryText,
CASE WHEN (A.GRP = 1)
THEN MAX(C.Lineage)
ELSE MAX(A.Lineage)
END AS Lineage,
CASE WHEN (A.GRP = 1)
THEN C.SortOrder * 100
ELSE MAX(A.SortOrder)
END AS SortOrder,
SUM(Quantity) AS Quantity,
SUM(Price) AS Price,
SUM(Cost) AS Cost
FROM tbl_Categories C RIGHT JOIN
(
SELECT
SP.SalesID,
MAX(P.CategoryID) AS ParentID,
SUM(SP.Quantity) AS Quantity,
SUM(SP.Price) AS Price,
SUM(SP.Cost) AS Cost,
CASE WHEN (GROUPING(P.Product) = 1)
THEN CASE WHEN(C.Lineage IS NULL)
THEN 0
ELSE Max(C.SortOrder) * 100
END
ELSE (Max(C.SortOrder) * 100) + 1
END AS SortOrder,
GROUPING(P.Product) as grp,
GROUPING(SP.Price) as grp2,
P.Product,
CASE WHEN (GROUPING(P.Product) = 1)
THEN C.Lineage
ELSE 'X.' + C.Lineage
END AS Lineage,
CASE WHEN(GROUPING(P.Product) = 1)
THEN CASE WHEN(C.Lineage IS NULL)
THEN NULL
ELSE MAX(C.CategoryText)
END
ELSE ISNULL(P.Product, 'UNKNOWN')
END AS Category
FROM tbl_Sales SP INNER JOIN
tbl_Products P ON SP.ProductID = P.ProductID INNER JOIN
tbl_Categories C ON P.CategoryID = C.CategoryID
GROUP BY SP.SalesID, C.Lineage, P.Product, SP.Price WITH ROLLUP
HAVING ((GROUPING(SP.Price) = 0) OR (GROUPING(SP.Price) = GROUPING(P.Product)))
) A
ON SUBSTRING(A.Lineage, 0, LEN(C.Lineage) + 1) = C.Lineage
GROUP BY A.SalesID, C.ParentID, C.CategoryID, C.CategoryText,
C.SortOrder, A.Product, A.GRP, A.Price
) Z
WHERE CategoryID IS NOT NULL
ORDER BY SalesID DESC, SortOrder, Price

derrickleggett
Pointy Haired Yak DBA

4184 Posts

Posted - 2005-09-12 : 01:43:12
I'll think about this a little bit more tomorrow when I'm not tired. I believe this will get you what you are wanting for right now.



DECLARE @Category TABLE(CategoryID INT, ParentID INT, CategoryText VARCHAR(55), Lineage VARCHAR(55), SortOrder INT)

INSERT @Category(CategoryID, ParentID, CategoryText, Lineage, SortOrder)
SELECT 1, 0, 'All', '1', 0 UNION ALL
SELECT 2, 1, 'Beer', '1.1', 1 UNION ALL
SELECT 3, 2, 'Domestic', '1.1.1', 2 UNION ALL
SELECT 37, 1, 'Wine', '1.4', 38 UNION ALL
SELECT 38, 37, 'Domestic', '1.4.1', 39 UNION ALL
SELECT 39, 38, 'California', '1.4.1.1', 40

DECLARE @Sales TABLE(SalesID INT, ProductID INT, Quantity INT, Price MONEY, Cost MONEY)

INSERT @Sales(SalesID, ProductID, Quantity, Price, Cost)
SELECT 20935, 1554, 1, 6.99, 4.91 UNION ALL
SELECT 20935, 721, 1, 10.99, 8 UNION ALL
SELECT 20934, 786, 1, 9.99, 7.35 UNION ALL
SELECT 20934, 786, 2, 9.99, 7.35 UNION ALL
SELECT 20933, 1554, 1, 6.99, 4.91 UNION ALL
SELECT 20933, 1554, 1, 5.99, 4.91 --UNION ALL
-- SELECT 20933, 1554, 1, 5.99, 4.91

DECLARE @Products TABLE(ProductID INT, Product VARCHAR(55), CategoryID INT)

INSERT @Products(ProductID, Product, CategoryID)
SELECT 1554, 'Woodbridge Chardonnay, 750 ml', 39 UNION ALL
SELECT 721, 'SHARPE HILL RED SERAPH, 750 ml', 38 UNION ALL
SELECT 786, 'BUD , 12 oz 12 pack Bottle(s)', 3

SELECT
SalesID,
CategoryID,
ParentID,
CategoryText,
Lineage,
SortOrder,
SUM(Quantity) AS Quantity,
SUM(Price) AS Price,
SUM(Cost) AS Cost,
PriceMonitor
FROM (
SELECT
A.PriceMonitor,
A.SalesID,
CASE
WHEN (A.GRP = 1) THEN C.CategoryID
ELSE -1
END AS CategoryID,
CASE
WHEN (A.GRP = 1) THEN C.ParentID
ELSE Max(ISNULL(A.ParentID,0))
END AS ParentID,
CASE
WHEN (A.GRP = 1) THEN C.CategoryText
ELSE A.Product
END AS CategoryText,
CASE
WHEN (A.GRP = 1) THEN MAX(ISNULL(C.Lineage,0))
ELSE MAX(A.Lineage)
END AS Lineage,
CASE
WHEN (A.GRP = 1) THEN ISNULL(C.SortOrder,0) * 100
ELSE MAX(A.SortOrder)
END AS SortOrder,
SUM(Quantity) AS Quantity,
SUM(Price) AS Price,
SUM(Cost) AS Cost
FROM
@Category C
RIGHT JOIN (
SELECT
CASE
WHEN P.CategoryID <> -1 THEN Price
ELSE P.CategoryID
END AS PriceMonitor,
SP.SalesID,
MAX(P.CategoryID) AS ParentID,
SUM(SP.Quantity) AS Quantity,
SUM(SP.Price*SP.Quantity) AS Price,
SUM(SP.Cost*SP.Quantity) AS Cost,
CASE
WHEN (GROUPING(P.Product) = 1) THEN
CASE
WHEN(C.Lineage IS NULL) THEN 0
ELSE Max(C.SortOrder) * 100
END
ELSE (Max(C.SortOrder) * 100) + 1
END AS SortOrder,
GROUPING(P.Product) as grp,
GROUPING(SP.Price) as grp2,
P.Product AS Product,
CASE
WHEN (GROUPING(P.Product) = 1) THEN ISNULL(C.Lineage,0)
ELSE 'X.' + ISNULL(C.Lineage,0)
END AS Lineage,
CASE
WHEN(GROUPING(P.Product) = 1) THEN
CASE
WHEN(C.Lineage IS NULL) THEN 'UNKNOWN'
ELSE MAX(C.CategoryText)
END
ELSE ISNULL(P.Product, 'UNKNOWN')
END AS Category
FROM
@Sales SP
INNER JOIN @Products P ON SP.ProductID = P.ProductID
INNER JOIN @Category C ON P.CategoryID = C.CategoryID
GROUP BY
SP.SalesID,
C.Lineage,
P.Product,
SP.Price,
P.CategoryID
WITH ROLLUP
HAVING
((GROUPING(SP.Price) = 0)
OR (GROUPING(SP.Price) = GROUPING(P.Product)))
) A ON SUBSTRING(A.Lineage, 0, LEN(C.Lineage) + 1) = C.Lineage
GROUP BY
A.SalesID,
C.ParentID,
C.CategoryID,
C.CategoryText,
C.SortOrder,
A.Product,
A.GRP,
A.Price,
A.PriceMonitor) Z
WHERE
CategoryID IS NOT NULL
AND (CategoryID <> -1 OR PriceMonitor IS NOT NULL)
GROUP BY
SalesID,
CategoryID,
ParentID,
CategoryText,
Lineage,
SortOrder,
PriceMonitor
ORDER BY
SalesID DESC,
SortOrder,
Price




You had a few issues:

1. You were eliminating NULLs by not having ISNULL around all your numeric aggregates. In most cases, this would still produce the same result, but it would be annoying for any application actually trying to use this.

2. You weren't grouping out the individual product prices, so there was no way to differentiate between the same products with different prices.

3. The top level of your query wasn't being aggregated, so you had a bunch of duplicates showing up, since anything not aggregated must appear in the GROUP BY clause. I might be wrong on this one since I'm tired.

4. I don't believe you were aggregating the prices correctly in the original derived table. I placed logic to multiply cost and price by the quantity.


Forgive me if this is completely off base. I should have gone to bed earlier. lol

MeanOldDBA
derrickleggett@hotmail.com

When life gives you a lemon, fire the DBA.
Go to Top of Page

rythm123us
Starting Member

27 Posts

Posted - 2005-09-12 : 10:25:06
Thanks it gives me the results I was looking for. I will take a better look at the query and my mistakes when I have sometime later this week.

As far as your cooment 4
quote:

4. I don't believe you were aggregating the prices correctly in the original derived table. I placed logic to multiply cost and price by the quantity.



This was done on purpose. The multiplication was not performed, so that the user can see the original Price of the Product and the Multiplication could be done on client side.

If you are this good when you are tired, you must be GREAT when you are not.

One more question was I on the right path with ROLLUP or was the query unnecessarily complicated. In simple terms is there a better way?

Thanks for your help.

If you could guide me towards some sites to increase my knowledge that would be veru helpful.
Go to Top of Page

rythm123us
Starting Member

27 Posts

Posted - 2005-09-12 : 21:52:00
Actually I thought of something else and will try it on Thursday, but if you think this would be intriguing and would like to help that would be great.

1. I would like to set the order in this manner.
OrderID, CategoryID and then the Products will be ordered by SUM of Quantity for a Prodct, then Price
Example:
INSERT @Products(ProductID, Product, CategoryID)
SELECT 1555, 'Woodbridge Chardonnay, 1.5 L', 39

INSERT @Sales(SalesID, ProductID, Quantity, Price, Cost)
SELECT 20936, 1554, 2, 6.99, 4.91 UNION ALL
SELECT 20936, 1555, 5, 11.99, 9.54 UNION ALL
SELECT 20936, 1554, 4, 5.99, 4.91

This would show up in this order
Woodbridge Chardonnay 750 ml, 4, 5.99, 4.91
Woodbridge Chardonnay 750 ml, 2, 6.99, 4.91
Woodbridge Chardonnay 1.5 L, 5, 11.99, 9.54

It is in this order because the combined total of "Woodbridge Chardonnay 750 ml(ProductID:1554)" is greater than "Woodbridge Chardonnay 750 ml(ProductID: 1555)".

2. Add 2 Percentage fields to the final query. One showing the Percentage of the Price within the given category and the other showing the Percentage of the Price compared to the entire Total(All).

I have no idea how, but I will give it a try. Should be fun and frustrating at the same time.

Thanks again...
rythm

Go to Top of Page

derrickleggett
Pointy Haired Yak DBA

4184 Posts

Posted - 2005-09-12 : 22:37:15
I might mess around with it this weekend just for fun. lol



MeanOldDBA
derrickleggett@hotmail.com

When life gives you a lemon, fire the DBA.
Go to Top of Page

rythm123us
Starting Member

27 Posts

Posted - 2005-09-13 : 00:13:56
When life gives you a lemon, fire the DBA.

I don't get that
Go to Top of Page

derrickleggett
Pointy Haired Yak DBA

4184 Posts

Posted - 2005-09-13 : 11:38:37
You haven't been a DBA very long have you?

MeanOldDBA
derrickleggett@hotmail.com

When life gives you a lemon, fire the DBA.
Go to Top of Page

rythm123us
Starting Member

27 Posts

Posted - 2005-09-13 : 23:11:40
I have done very little DBA work. I know a decent amount of SQL. Have worked with Oracle, SQL, and DB2. Mostly developing in all of these, but very little maintanenace. However, I always tried my best to understand the important topics to produce better results, and recently have been thinking of shifting my carrer from a Developer to a DBA. Any advice??
Go to Top of Page

rythm123us
Starting Member

27 Posts

Posted - 2005-09-17 : 12:37:31
i just created a new POST for the Percentage and SUM question. It is a different topic so I thought that would be best.

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=55311
Go to Top of Page

derrickleggett
Pointy Haired Yak DBA

4184 Posts

Posted - 2005-09-17 : 15:44:22
You have some interesting posts rythm. I wish that I had more time to spend on them. lol If you want to transition to a DBA, I would buy "Inside SQL Server" by Kalen Delaney, any book by Ken Henderson, the Performance Tuning Manual by Microsoft Press, and the 911 Admin book. There's always a demand for a really good DBA. Just determine to not be mediocre.

Also, you need to really learn SQL and database relational theory. Learn how these things work on under the covers. You'll be a better DBA, developer, or programmer if you do.

MeanOldDBA
derrickleggett@hotmail.com

When life gives you a lemon, fire the DBA.
Go to Top of Page
   

- Advertisement -