简体   繁体   中英

MySQL selecting rows based on condition of additional table

To summarize, I have several companies that own multiple sites and multiple divisions. Each division has one or more sites. I am reusing the division and site tables for all companies. I essentially have a global pool of divisions and sites for each company to pull from. My end goal is to pull all of the sites belonging to a division of a company.

Company 1  
   |  
   + Division 1  
   |      |  
   |      + Site 1  
   |      + Site 2  
   |
   + Division 2  
   |  
Company 2
   |
   + Division 3  
   |      |  
   |      + Site 3  
   |      + Site 2 
   | 
   + Division 1  
   |

company

+----+-------------+  
| id |    name     |  
+----+-------------+ 
| 1  |  company 1  |
+----+-------------+
| 2  |  company 2  |
+----+-------------+ 

sites

+----+-------------+  
| id |    name     |  
+----+-------------+ 
| 1  |   site 1    |
+----+-------------+
| 2  |   site 2    |
+----+-------------+
| 3  |   site 3    |
+----+-------------+

divisions

+----+-----------------+  
| id |      name       |  
+----+-----------------+ 
| 1  |   division 1    |
+----+-----------------+
| 2  |   division 2    |
+----+-----------------+
| 3  |   division 3    |
+----+-----------------+

company_divisions

+----------+--------------+  
| company  |   division   |  
+----------+--------------+ 
|     1    |       1      |
+----------+--------------+
|     1    |       2      |
+----------+--------------+
|     2    |       1      |
+----------+--------------+
|     2    |       3      |
+----------+--------------+

company_sites

+----------+------------+  
| company  |   site     |  
+----------+------------+ 
|     1    |     1      |
+----------+------------+
|     1    |     2      |
+----------+------------+
|     2    |     2      |
+----------+------------+
|     2    |     3      |
+----------+------------+

I originally thought I could select all of the sites constrained by a company.id and division.id but I have had no such luck. I have attempted sub queries:

select * 
from sites 
where id IN (select site from company_sites where company = 3)

and joins:

select s.* 
from sites s 
inner join company_sites cs on s.id = cs.site 
where cs.company = 3

but these results only relate to the company_site and not the division . I can't seem to figure out how to get the company_divisions table involved.. something like this:

select s.* 
from sites s 
inner join company_sites cs on s.id = cs.site 
inner join company_divisions cd on divisions.id = cd.division 
where cs.company = 2 AND cd.division = 3

How can I add an additional condition or query that ensures that the same company.id that was used to select the site in company_sites relates to a company.id in company_division via the division.id ?

For example given company.id = 2 and division.id = 3 I would expect a result of site 2 and site 3 .

Constructive criticism is always welcome.

For such tree structure, I would probably remove company_divisions and company_sites table and design it as such.

company
+----+-------------+  
| id |    name     |  
+----+-------------+ 
| 1  |  company 1  |
+----+-------------+
| 2  |  company 2  |
+----+-------------+
name should be unique, id is the primary key 

divisions
+----+-----------------+-------------+  
| id |      name       | company id  |
+----+-----------------+-------------+
| 1  |   division 1    |      1      |
+----+-----------------+-------------+
| 2  |   division 2    |      1      |
+----+-----------------+-------------+
| 3  |   division 3    |      2      |
+----+-----------------+-------------+
| 4  |   division 1    |      2      |
+----+-----------------+-------------+
id is the primary key, company id is foreign key referenced to company.id.

sites
+----+-------------+-------------+
| id |    name     | division id |
+----+-------------+-------------+
| 1  |   site 1    |      1      |
+----+-------------+-------------+
| 2  |   site 2    |      1      |
+----+-------------+-------------+
| 3  |   site 3    |      3      |
+----+-------------+-------------+
| 4  |   site 2    |      3      |
+----+-------------+-------------+
id is the primary key, division id  is foreign key referenced to divisions.id.

Using the query

SELECT 
    sites.name as `site`, 
    divisions.name as `division`, 
    company.name as `company` 
FROM sites
LEFT JOIN divisions ON sites.`division id` = divisions.id
LEFT JOIN company ON divisions.`company id` = company.id

would give

+-------------+------------+-----------+
|    site     |  division  |  company  |
+-------------+------------+-----------+
|   site 1    | division 1 | company 1 |
+-------------+------------+-----------+
|   site 2    | division 1 | company 1 |
+-------------+------------+-----------+
|   site 3    | division 3 | company 2 |
+-------------+------------+-----------+
|   site 2    | division 3 | company 2 |
+-------------+------------+-----------+

Filtering from here onward should be quite easy, just add WHERE conditions behind.

I would suggest this, If you can modify the structure and have separate division site mapping table. This would also allow a site to belong to multiple divisions to multiple sites.

Company Table:

+----+-------------+  
| id |    name     |  
+----+-------------+ 
| 1  |  company_1  |
+----+-------------+
| 2  |  company_2  |
+----+-------------+ 

Division Table :

+----+-------------+--------------+  
| id |    name     |  company_id  |
+----+-------------+ -------------+
| 1  |  division 1 |      1       |
+----+-------------+--------------+
| 2  |  division 2 |      2       |
+----+-------------+--------------+ 
| 3  |  division 3 |      2       |
+----+-------------+--------------+ 
| 4  |  division 4 |      3       |
+----+-------------+--------------+ 

Sites Table :

+----+----------------------+
| id |    url               |
+----+----------------------+ 
| 1  |  http:\www.url1.com  |
+----+----------------------+ 
| 2  |  http:\www.url2.com  |
+----+----------------------+
| 3  |  http:\www.url3.com  |
+----+----------------------+
| 4  |  http:\www.url4.com  |
+----+----------------------+

division_site Table :

+----+-------------+--------------+  
| id |    div_id   |  site_id     |
+----+-------------+ -------------+
| 1  |       1     |      1       |
+----+-------------+--------------+
| 2  |       1     |      2       |
+----+-------------+--------------+
| 3  |       2     |      1       |
+----+-------------+--------------+
| 4  |       2     |      3       |
+----+-------------+--------------+
| 5  |       2     |      4       |
+----+-------------+--------------+
| 6  |       3     |      1       |
+----+-------------+--------------+
| 7  |       4     |      2       |
+----+-------------+--------------+

So you can have something like :

select company.name as company_name ,division.name as division_name ,GROUP_CONCAT(sites.url) as "Site URL's" from company inner join division on division.company_id = company.id left JOIN div_sites on div_sites.div_id = division.id inner join sites on sites.id = div_sites.site_id where company.id = 1 and division.id =1 GROUP by division.id

Which would return

+----+-------------+-------------------+-----------------------+  
| company name     |    division name  |    Url's              |
+----+-------------+-------------------+------------------------
|   company_1      |    div 1          | http:\www.url1.com,   |
|                  |                   | http:\www.url2.co     |
+------------------+-------------------+-----------------------+  

the code you have given in something like this, checks for company_site.company=3 ,a value that doesn't exist in your table. Similarly with company_divisions table. In fact, there is no company 3. Try for data that exists

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