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.