1

I have the following tables:

  1. Category table which has an ID column, a description column, and category parent ID columns as follows:

cat_id | cat_description | cat_pid
-------+-----------------+--------
1      | State           | 0
2      | Texas           | 1
3      | California      | 1
4      | Title           | 0
5      | Engineer        | 4
6      | Lawyer          | 4
7      | Farmer          | 4
8      | Credit Card     | 0
9      | Visa            | 8
10     | Master Card     | 8
...
2. Customer table which has customer ID and name as follows:

cust_id | cust_name
--------+----------- 111111 | John 222222 | David 333333 | Chris 444444 | Mark ...
3. Category_Has_Customer which is many to many relationship between Customer and Category.

chc_cust_id | chc_cat_id
------------+-----------
111111      | 2
111111      | 5
111111      | 9
222222      | 7
222222      | 3
333333      | 6
The category has only two levels depth.

In my application, a customer could have zero or more categories. I would like to display some or all of the categories, which the customer has. For example if I choose to display all categories I would like to have the following table:

cust_name | State      | Title    | Credit Card
----------+------------+----------+------------
John      | Texas      | Engineer | Visa
David     | California | Farmer   |
Chris     |            | Lawyer   |
Mark      |            |          |
I should also be able to display certain categories, for example Title and Credit Card only:

cust_name | Title    | Credit Card
----------+----------+------------
John      | Engineer | Visa
David     | Farmer   |
Chris     | Lawyer   |
Mark      |          |

I tried to do it with LEFT JOIN's, something like:

SELECT c1.cust_id, c1.cust_name, t1.cat_desc as State
FROM Customer c1, Category_has_Customer chc
LEFT JOIN Category t1 ON t1.cat_pid = '1' AND chc.chc_cat_id = t1.cat_id
WHERE c1.cust_id = chc.chc_cust_id

But it didn't help since I got duplicated rows.

Cœur
  • 37,241
  • 25
  • 195
  • 267
user979353
  • 13
  • 2

1 Answers1

0

I'll give this a go, should work on all sql implemtations but I've done in in t-sql:

With this data

declare @Category table (cat_id int, cat_description varchar(20), cat_pid int)
declare @Customer table (cust_id int, cust_name varchar(20))
declare @Customer_Has_Category table (chc_cust_id int, chc_cat_id int)

insert into @Category (cat_id, cat_description, cat_pid) values (1,'State',0)
insert into @Category (cat_id, cat_description, cat_pid) values (2,'Texas',1)
insert into @Category (cat_id, cat_description, cat_pid) values (3,'California',1)
insert into @Category (cat_id, cat_description, cat_pid) values (4,'Title',0)
insert into @Category (cat_id, cat_description, cat_pid) values (5,'Engineer',4)
insert into @Category (cat_id, cat_description, cat_pid) values (6,'Lawyer',4)
insert into @Category (cat_id, cat_description, cat_pid) values (7,'Farmer',4)
insert into @Category (cat_id, cat_description, cat_pid) values (8,'Credit Card',0)
insert into @Category (cat_id, cat_description, cat_pid) values (9,'Visa',8)
insert into @Category (cat_id, cat_description, cat_pid) values (10,'Master Card',8)

insert into @Customer (cust_id, cust_name) values (111111, 'John')
insert into @Customer (cust_id, cust_name) values (222222, 'David')
insert into @Customer (cust_id, cust_name) values (333333, 'Chris')
insert into @Customer (cust_id, cust_name) values (444444, 'Mark')

insert into @Customer_Has_Category (chc_cust_id, chc_cat_id) values (111111, 2)
insert into @Customer_Has_Category (chc_cust_id, chc_cat_id) values (111111, 5)
insert into @Customer_Has_Category (chc_cust_id, chc_cat_id) values (111111, 9)
insert into @Customer_Has_Category (chc_cust_id, chc_cat_id) values (222222, 7)
insert into @Customer_Has_Category (chc_cust_id, chc_cat_id) values (222222, 3)
insert into @Customer_Has_Category (chc_cust_id, chc_cat_id) values (333333, 6)

This query

select cust_name, MAX(State) as State, MAX(Title) as Title, MAX(CreditCard) as CreditCard
from
(
select 
c.cust_name,
(case when cat.cat_pid = 1 then cat_description else '' end) as State,
(case when cat.cat_pid = 4 then cat_description else '' end) as Title,
(case when cat.cat_pid = 8 then cat_description else '' end) as CreditCard
from @Customer c 
left outer join @Customer_Has_Category chc on c.cust_id = chc.chc_cust_id
left outer join @Category cat on chc.chc_cat_id = cat.cat_id
) as subq
group by cust_name

Gives

cust_name            State                Title                CreditCard
-------------------- -------------------- -------------------- --------------------
Chris                                     Lawyer               
David                California           Farmer               
John                 Texas                Engineer             Visa
Mark   

If you want to take out the State just remove it from the select statement.

amelvin
  • 8,919
  • 4
  • 38
  • 59
  • Thanks amelvin a lot for your prompt response ! This is exactly what I was looking for :) – user979353 Oct 05 '11 at 10:50
  • It sure does :) I tried to do it for a week and searched the Web but with no luck. Now the problem is solved thanks to you – user979353 Oct 05 '11 at 10:57
  • Good to know, hopefully you will come to StackOverflow more quickly next time! You might want to read the site faq (http://stackoverflow.com/faq#howtoask) regarding what you should do when you ask a question and get answers back if you are planning on becoming a regular. – amelvin Oct 05 '11 at 11:21
  • Hey amelvin, I was wondering if you can provide an explanation about the query you suggested. I didn't quite understand why we need the MAX and GROUP BY. Understanding this will help me in future designs. Thanks in advance! – user979353 Oct 11 '11 at 11:12
  • NP. If you run the inner sql query (in the bracket starting **select c.cust_name** and ending before **) as subq**) you will see it produces 3 rows for John, 2 for David etc - so the group by bundles the 3 John rows together and the MAX chooses whichever of the rows actually has a value. HTH – amelvin Oct 11 '11 at 12:55