简体   繁体   中英

Joining one table through other tables to another

I am struggling to articulate in a search query what I'm trying to do so I'm sorry if this has been answered before. I'm hoping that by posting a full example someone will be able to point me in the right direction. I'm looking to either figure out a mySQL query, or learn a better way to structure my database, to make the following possible.

If I have 4 tables, what is the best way to link through a table to another. Below I have a site_table that has an ID for a manager (General Manager of the site), a region and a country. The region_table and country_table also point at the manager_table. The manager_id on the site_table also points at the manager_table. Here are what the tables may look like:

site_table
+------------+------------+-----------+------------+
|    name    | manager_id | region_id | country_id |
+------------+------------+-----------+------------+
| Manchester |          1 |         1 |          1 |
| Essex      |          2 |         2 |          1 |
| Perth      |          3 |         3 |          2 |
| Birmingham |          4 |         1 |          1 |
+------------+------------+-----------+------------+

region_table
+-----------+---------+------------+
| region_id |  name   | manager_id |
+-----------+---------+------------+
|         1 | Central |          5 |
|         2 | South   |          6 |
|         3 | North   |          7 |
+-----------+---------+------------+

country_table
+------------+----------+------------+
| country_id |   name   | manager_id |
+------------+----------+------------+
|          1 | England  |          9 |
|          2 | Scotland |          8 |
+------------+----------+------------+

manager_table
+------------+-----------------+
| manager_id |      name       |
+------------+-----------------+
|          1 | Joe Bloggs      |
|          2 | Graham Smith    |
|          3 | Pat Sharp       |
|          4 | Sally May       |
|          5 | Peter Barratt   |
|          6 | Jimmy Stone     |
|          7 | Kim Keller      |
|          8 | Peter Sheet     |
|          9 | Matthew Lampart |
+------------+-----------------+

I would like to query the database to return the site name, General Manager's (GM) name, Regional Manager's (RM) name and Country Manager's (CM) name like so:

+------------+--------------+---------------+-----------------+
| site_name  |   GM_name    |    RM_name    |     CM_name     |
+------------+--------------+---------------+-----------------+
| Manchester | Joe Bloggs   | Peter Barratt | Matthew Lampart |
| Essex      | Graham Smith | Jimmy Stone   | Matthew Lampart |
| Perth      | Pat Sharp    | Kim Keller    | Peter Sheet     |
| Birmingham | Sally May    | Peter Barratt | Matthew Lampart |
+------------+--------------+---------------+-----------------+

I feel like to do this I would have to link the site_table to the region_table and country_table, and then link the manager_table to the site_table, region_table and country_table but I'm tying myself up in knots trying to do it. I see the links looking like this:

site_table---+-----------------------+
             |                       |
             +-----region_table----manager_table
             |                       |
             +----country_table------+

If anyone can give any advice on the best way to write this query, or a better way to structure the database, that would be really helpful.

So the straightforward answer is:

select
  s.name site_name,
  gm.name GM_name,
  rm.name RM_name,
  cm.name CM_name
from
  site_table s
  inner join manager_table gm on gm.manager_id = s.manager_id
  inner join region_table r on r.region_id = s.region_id
  inner join manager_table rm on rm.manager_id = r.manager_id
  inner join country_table c on c.country_id = s.country_id
  inner join manager_table cm on cm.manager_id = c.manager_id;

But this really only works if there's always at least one region and manager for each GM, RM, and CM. Something a little more flexible might be:

select
  s.name site_name,
  gm.name GM_name,
  rm.name RM_name,
  cm.name CM_name
from
  site_table s
  left outer join manager_table gm on gm.manager_id = s.manager_id
  left outer join region_table r on r.region_id = s.region_id
  left outer join manager_table rm on rm.manager_id = r.manager_id
  left outer join country_table c on c.country_id = s.country_id
  left outer join manager_table cm on cm.manager_id = c.manager_id;

Which will handle situations where you may be missing managers or regions, but is a little less efficient.

Hope these help!

Try using conditional aggregation using CASE EXPRESSION . Your idea is correct, you need to join first all three tables, and then as you can see I joined to manager tables on m.manager_id IN(s.manager_id,r.manager_id,c.manager_id) . The aggregation after is to pivot the output since there will be 3 records for each name, containing manager_name for each one of the tables.

SELECT s.name,
      MAX(CASE WHEN s.manager_id = m.manager_id THEN m.name END) as GM_NAME,
      MAX(CASE WHEN r.manager_id= m.manager_id THEN m.name END) as RM_NAME,
      MAX(CASE WHEN c.manager_id = m.manager_id THEN m.name END) as CM_NAME
FROM site_table s
INNER JOIN region_table r ON(s.region_id = r.region_id)
INNER JOIN country_table c ON(s.country_id = c.country_id)
INNER JOIN manager_table m ON(m.manager_id IN(s.manager_id,r.manager_id,c.manager_id))
GROUP BY s.name

If you can have missing data - nulls on any of the site_table id columns, which doesn't sound very reasonable by the data you provided and even by the idea of this structure, then use a left join

SELECT s.name,
      MAX(CASE WHEN s.manager_id = m.manager_id THEN m.name END) as GM_NAME,
      MAX(CASE WHEN r.manager_id= m.manager_id THEN m.name END) as RM_NAME,
      MAX(CASE WHEN c.manager_id = m.manager_id THEN m.name END) as CM_NAME
FROM site_table s
LEFT JOIN region_table r ON(s.region_id = r.region_id)
LEFT JOIN country_table c ON(s.country_id = c.country_id)
LEFT JOIN manager_table m ON(m.manager_id IN(s.manager_id,r.manager_id,c.manager_id))
GROUP BY s.name

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