| Author |
Topic |
|
hoghunter
Starting Member
9 Posts |
Posted - 2004-08-09 : 11:34:54
|
Here's a challenge for all you SQL gurus out there. I have two tables:CREATE TABLE XMAS_ITEMS(ITEM_NO CHAR(12) NOT NULL,ITEM_DESC CHAR(30) NULL)CREATE TABLE ORDER_ITEM_SUM(CUST_NO CHAR(15) NOT NULL,ITEM_NO CHAR(12) NOT NULL,QTY_ORDERED INT NULL) XMAS_ITEMS Contains the list of valid Christmas inventory items.ORDER_ITEM_SUM Contains a list of each customer's previous year's Christmas order and the qty ordered per item.Individual customers will not have ordered all items, yet all items were ordered by at least one customer. I would like to get a list of all Christmas items and how many were ordered by a given cutomer. Assume:XMAS_ITEMS:ITEM_NO ITEM_DESC1 Large Bags2 Medium Bags3 Large Boxes4 Medium Boxes ORDER_ITEM_SUM:CUST ITEM QTY1 -- 1 -- 101 -- 2 -- 151 -- 4 -- 202 -- 3 -- 302 -- 4 -- 403 -- 1 -- 203 -- 2 -- 503 -- 3 -- 10The result of my query should look like:CUST ITEM QTY1 -- 1 -- 101 -- 2 -- 151 -- 3 -- 01 -- 4 -- 202 -- 1 -- 02 -- 2 -- 02 -- 3 -- 302 -- 4 -- 403 -- 1 -- 203 -- 2 -- 503 -- 3 -- 103 -- 4 -- 0 Currently, I am doing this using a set of nested cursors that loops through XMAS_ITEMS then through ORDER_ITEM_SUM for each customer.I seem to recall having read a solution to this problem in a Joe Celko book but I loaned my books out. Any help will be appreciated. |
|
|
ditch
Master Smack Fu Yak Hacker
1466 Posts |
Posted - 2004-08-09 : 12:25:14
|
| Maybe I am misunderstanding the question - But I don't see why you even thought of using a cursor(That is a dirty word here).SELECT c.Cust, i.Item, SUM(ISNULL(o.QTY, 0)) as QTYFROM (SELECT DISTINCT CUST FROM ORDER_ITEM_SUM) cCROSS JOIN XMAS_Items iLEFT OUTER JOIN ORDER_ITEM_SUM o on o.Cust = c.CustAND o.Item = i.ItemDuane. |
 |
|
|
mfemenel
Professor Frink
1421 Posts |
Posted - 2004-08-09 : 12:29:26
|
| Maybe it's just 'cause this is monday, but wouldn't this work?select ois.cust_no,xi.item_no,sum(isnull(ois.qty_ordered,0)) from order_item_sum ois left join xmas_items xi on ois.item_no=xi.item_no group by ois.cust_no,xi.item_noMike"oh, that monkey is going to pay" |
 |
|
|
mfemenel
Professor Frink
1421 Posts |
Posted - 2004-08-09 : 12:30:07
|
| Maybe it's just 'cause this is monday, but wouldn't this work?select ois.cust_no,xi.item_no,sum(isnull(ois.qty_ordered,0)) from order_item_sum ois left join xmas_items xi on ois.item_no=xi.item_no group by ois.cust_no,xi.item_noMike"oh, that monkey is going to pay" |
 |
|
|
Nedra
Starting Member
21 Posts |
Posted - 2004-08-09 : 12:42:06
|
| Here's a solutionselect distinct ois.Cust_No , xi.Item_No , case when ois.Item_No = xi.Item_No then ois.Qty_Ordered else 0 end from ORDER_ITEM_SUM as ois inner join XMAS_ITEMS as xi on ois.ITEM_NO = case when not exists (select ITEM_NO from ORDER_ITEM_SUM where Cust_No = ois.Cust_No and ITEM_NO = xi.ITEM_NO) then ois.ITEM_NO else xi.ITEM_NO end order by cust_no , xi.item_noProbably not the best performing, but better then a nested cursor! |
 |
|
|
Nedra
Starting Member
21 Posts |
Posted - 2004-08-09 : 12:52:07
|
| I compared my solution to ditch's solutionSELECT c.Cust_No, i.Item_No, SUM(ISNULL(o.Qty_Ordered, 0)) as QTYFROM (SELECT DISTINCT CUST_No FROM ORDER_ITEM_SUM) cCROSS JOIN XMAS_Items iLEFT OUTER JOIN ORDER_ITEM_SUM oon o.Cust_No = c.Cust_NoAND o.Item_No = i.Item_Nogroup by c.Cust_No, i.Item_Noorder by c.Cust_No, i.Item_No(had to add the group by and order by to get it to work)They are comperable in estimated query plans, with my initial solution edging it slightly. Larger amounts of data and proper indexing would probably give a truer estimation. |
 |
|
|
hoghunter
Starting Member
9 Posts |
Posted - 2004-08-09 : 13:26:18
|
quote: Originally posted by ditch Maybe I am misunderstanding the question - But I don't see why you even thought of using a cursor(That is a dirty word here).
I totally agree, cursors are BAD. As a matter of fact, in my role as data architect, I have made the statement that I have NEVER found a problem that required the use of a cursor. Having said that, this problem came up on Friday (late in the day) and since it only needs to run once a year, there will be no performance impact associated with the cursors.quote: SELECT c.Cust, i.Item, SUM(ISNULL(o.QTY, 0)) as QTYFROM (SELECT DISTINCT CUST FROM ORDER_ITEM_SUM) cCROSS JOIN XMAS_Items iLEFT OUTER JOIN ORDER_ITEM_SUM o on o.Cust = c.CustAND o.Item = i.Item
That works! Thanks. I have never used a cross join before, this looks like the solution I had read in Joe's book. |
 |
|
|
hoghunter
Starting Member
9 Posts |
Posted - 2004-08-09 : 13:28:34
|
quote: Originally posted by mfemenel Maybe it's just 'cause this is monday, but wouldn't this work?select ois.cust_no,xi.item_no,sum(isnull(ois.qty_ordered,0)) from order_item_sum ois left join xmas_items xi on ois.item_no=xi.item_no group by ois.cust_no,xi.item_noMike"oh, that monkey is going to pay"
In the case of cust 1, there will be no item 3. The left join is satisfied for item 3 by the existence of item 3 for cust 2. |
 |
|
|
hoghunter
Starting Member
9 Posts |
Posted - 2004-08-09 : 14:07:37
|
quote: Originally posted by Nedra Here's a solutionselect distinct ois.Cust_No , xi.Item_No , case when ois.Item_No = xi.Item_No then ois.Qty_Ordered else 0 end from ORDER_ITEM_SUM as ois inner join XMAS_ITEMS as xi on ois.ITEM_NO = case when not exists (select ITEM_NO from ORDER_ITEM_SUM where Cust_No = ois.Cust_No and ITEM_NO = xi.ITEM_NO) then ois.ITEM_NO else xi.ITEM_NO end order by cust_no , xi.item_noProbably not the best performing, but better then a nested cursor!
This looks like the kind of query I was attempting to get working Friday. I kept getting wrapped up in the joins and sub selects I never consider the not exists concecpt. Nice, thank you. |
 |
|
|
|