tags:

views:

357

answers:

5

This might be a little hard to explain, but I will try.

I want to display a list of categories (stored in 1 table), and number of domains associated with each category (stored in another table).

The monkey wrench in this case is that each domain has a set of records associated with it (which are stored in a 3rd table). I only want to show the categories that have domains associated with them, and the count of domains should reflect only the domains that have records associated with them (from the 3rd table).

My current query

SELECT r.rev_id, c.cat_id, c.cat_name, count(d.dom_id) As rev_id_count FROM reviews r
INNER JOIN  domains d ON r.rev_domain_from=d.dom_id 
INNER JOIN  categories c ON d.dom_catid=c.cat_id  
WHERE rev_status = 1
GROUP BY cat_name  
ORDER BY cat_name

This selects the correct category names, but shows a false count (rev_id_count). If the category has 2 domains in it, and each domain has 2 records, it will show count of 4, when it should be 2.

+1  A: 

Something like this?

SELECT c.name, count(d.id)
FROM categories c
JOIN domains d ON c.id = d.cid
JOIN records r ON r.did = d.id
GROUP BY c.name;
AquilaX
Thats what I have right now. It doesn't display the correct counts for the domains. if I have 2 domains in a category, and each domain has 2 records, it will show count as 4, instead of 2.
Yegor
Does MySQL support COUNT(DISTINCT)? Then try COUNT(DISTINCT(d.id)).
Tomalak
Thanks Tamalak! That worked!
Yegor
You should accept it, then.
Tomalak
A: 

Start off by selecting the domain that has records - and then pull in the categories that match the domain.

so something like

 SELECT * FROM records 
    INNER JOIN domains on <clause> 
    INNER JOIN categories on <clause>
 WHERE <something>

I can't explain this too well, but all too often when writing SQL it is easy to look at things from the list of fields we want in the select and tend to use that to dictate the way we use the tables to build the data. In fact we should look more at how the data is related to the query we're building (which often seems back to front).

Richard Harrison
No effect. Same result as above.
Yegor
A: 

Extending on AquilaX's solution, you just need to select the name of the domain:

SELECT c.name, d.name, count(d.id)
  FROM categories c
    JOIN domains d ON c.id = d.cid
    JOIN records r ON r.did = d.id
GROUP BY c.name, d.name;

Which should show:

Cat 1, Domain 1, 2
Cat 1, Domain 2, 1
Cat 2, Domain 3, 5

etc...

(not tested though)

Mark
+2  A: 
select c.name, count(distinct d.did) from domains d
  left join categories c on c.cid = d.cid
  left join records r on r.did = d.did
  group by c.name

tested with 2 categories, 2 domains per categories, random number of records per domain. result set:

name     count
----     -----    
test     2
test2    2
Owen
+4  A: 
SELECT Categories.Name,count(DISTINCT categories.name) FROM Categories
JOIN Domains ON Categories.ID=Domains.CID
JOIN Records ON Records.DID=Domains.ID
GROUP BY Categories.Name

Tested with following setup:


CREATE TABLE Categories (Name nvarchar(50), ID int  NOT NULL IDENTITY(1,1))
CREATE TABLE Domains (Name nvarchar(50), ID int NOT NULL IDENTITY(1,1), CID int)
CREATE TABLE Records (Name nvarchar(50), ID int NOT NULL IDENTITY(1,1), DID int)

INSERT INTO Records (DID) VALUES (1)
INSERT INTO Records (DID) VALUES (1)
INSERT INTO Records (DID) VALUES (2)
INSERT INTO Records (DID) VALUES (2)
INSERT INTO Records (DID) VALUES (3)
INSERT INTO Records (DID) VALUES (3)

INSERT INTO Domains (Name,CID) VALUES ('D1',1)
INSERT INTO Domains (Name,CID) VALUES ('D2',1)
INSERT INTO Domains (Name,CID) VALUES ('D5',1)
INSERT INTO Domains (Name,CID) VALUES ('D3',2)
INSERT INTO Domains (Name,CID) VALUES ('D4',2)

INSERT INTO Categories (Name) VALUES ('1')
INSERT INTO Categories (Name) VALUES ('2')
INSERT INTO Categories (Name) VALUES ('3')
Mathias
The 'distinct' is key.
Ron Tuffin