简体   繁体   中英

How to combine multiple rows with multiple joins from multiple tables in mysql

I'm attempting to combine multiple rows into individual rows with multiple columns, where the data is from three tables. I followed the suggestions in MySQL pivot table but the question and answers do not account for multiple joins.

Here are the underlying tables:

table n
+------+----+------+
| name | id | code |
+------+----+------+
| foo  |  1 | NULL |
| bar  |  2 | z    |
| baz  |  3 | y    |
+------+----+------+

table ac
+------+----+
| code | id |
+------+----+
| h    |  1 |
| i    |  2 |
+------+----+

table c
+-----+------+-------+
| cid | code | desc  |
+-----+------+-------+
|   9 | h    | desch |
|   9 | i    | desci |
|   8 | z    | descz |
|   8 | y    | descy |
+-----+------+-------+

Here are the expected results:

+------+-------+-------+
| name | type8 | type9 |
+------+-------+-------+
| foo  | null  | desch |
| bar  | descz | desci |
| baz  | descy | null  |
+------+-------+-------+

I can get pretty close to the results I want with:

select 
n.name,
n.code as type8,
ac.code as type9
from n
left join ac
on ac.id=n.id

but as expected, this yields the codes only:

+------+-------+-------+
| name | type8 | type9 |
+------+-------+-------+
| foo  | null  | h     |
| bar  | z     | i     |
| baz  | y     | null  |
+------+-------+-------+

and I'm interested in replacing the codes with the longer descriptions from table c.

The first step is to use case to return multiple columns of data from multiple rows within the same table using the technique from pivot tables in mysql :

select
n.name,
case when c.cid=8 then c.desc end as type8,
case when c.cid=9 then c.desc end as type9
from n
left join c  
on n.code=c.code 

This yields the correct results for type8 but nulls for type9:

+------+-------+-------+
| name | type8 | type9 |
+------+-------+-------+
| foo  | null  | null  |
| bar  | descz | null  |
| baz  | descy | null  |
+------+-------+-------+

The next step is to get the results for type9:

select
n.name,
case when c.cid=8 then c.desc end as type8,
case when c.cid=9 then c.desc end as type9
from n
left join ac
on ac.id=n.id
left join c
on c.code=ac.code

This yields:

+------+-------+-------+
| name | type8 | type9 |
+------+-------+-------+
| foo  | null  | desch |
| bar  | null  | desci |
| baz  | null  | null  |
+------+-------+-------+

If these two results are unioned together with

select 
n.name,
case when c.cid=8 then c.desc end as type8,
case when c.cid=9 then c.desc end as type9
from n
left join c  
on n.code=c.code

union

select
n.name,
case when c.cid=8 then c.desc end as type8,
case when c.cid=9 then c.desc end as type9
from n
left join ac
on ac.id=n.id
left join c
on c.code=ac.code

the rows still need to be combined:

+------+-------+-------+
| name | type8 | type9 |
+------+-------+-------+
| bar  | descz | null  |
| baz  | descy | null  |
| foo  | null  | null  |
| foo  | null  | desch |
| bar  | null  | desci |
| baz  | null  | null  |
+------+-------+-------+

Finally, I was able to achieve the expected results by using the aggregating technique for removing nulls from a unioned query :

select 
n.name,
min(type8), min(type9)
from
(select 
n.name,
case when c.cid=8 then c.desc end as type8,
case when c.cid=9 then c.desc end as type9
from n
left join c  
on n.code=c.code

union
select
n.name,
case when c.cid=8 then c.desc end as type8,
case when c.cid=9 then c.desc end as type9
from n
left join ac
on ac.id=n.id
left join c
on c.code=ac.code) as n
group by n.name

which yields the results as expected:

+------+-------+-------+
| name | type8 | type9 |
+------+-------+-------+
| foo  | null  | desch |
| bar  | descz | desci |
| baz  | descy | null  |
+------+-------+-------+

Another way to get the desired results is to create a pseudo union by combining ifnull(.,.) with 2 left join statements and then aggregating the cid 's to mimic a pivot .

select name
    , min(if(cid = 8, `desc`, null)) Type8
    , min(if(cid = 9, `desc`, null)) Type9
from (
    select cid, code, `desc`, ifnull(name1, name2) name from (
        select c.cid, c.code, c.desc, n1.name name1, n2.name name2
        from c
        left join n n1 on n1.code = c.code
        left join ac on ac.code = c.code
        left join n n2 on n2.id = ac.id
    ) q1
) p1
group by name
order by 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