简体   繁体   中英

How would I write this 3 level deep mysql query?

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.

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')
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

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;

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).

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM