简体   繁体   中英

SQL - nested joins

I have a mySQL database in which I'm trying to output a list of users and their assigned, administrative roles. My tables look something like:

Users:
-------
- id
- fname
- lname


Role_Names
-----------
- rn_id
- role_name


Roles
---------
- role_id
- user_id

here's some data:

Users:
-------
1  'Chris'  'Christy'
2  'Brian'  'Bobson'
3  'Jen'    'Sanders'

Role_Names
--------------
1  'admin'
2  'exec'
3  'employee'

Roles
-----------
1   1
1   2
1   3
2   3
3   3
3   2

and for my query, I'm using:

SELECT Users.fname, Role_Names.role_name from Users INNER JOIN 
    Roles on Users.id = Roles.user_id
        INNER JOIN Role_Names
            ON Roles.rn_id = Roles.role_id;

It only seems to be outputting roles for the 1st user_id in the Roles table. And it's outputting more than 1 of the same record. For example, my output looks like:

first_name      role_name
--------------------------------------
Chris           exec
Chris           exec
Chris           exec
Chris           employee
Chris           employee
Chris           employee
Chris           admin
Chris           admin
Chris           admin

whereas I was hoping for something more like:

first_name      role_name
--------------------------------------
Chris           employee
Chris           admin
Chris           exec
Brian           employee
Jen             employee
Jen             exec
...

At tis point I'm not sure if it's my table structure that is flawed or if I'm using joins incorrectly or if it's that plus a bunch of other stuff I don't even know about. Can someone help point me in the right direction?

Stare at this piece of your query: ON Roles.rn_id = Roles.role_id;

It is not what you meant!

Here is the fixed query (with clearer formatting):

SELECT  Users.fname, Role_Names.role_name
    FROM        Users AS u
    INNER JOIN  Roles AS r        ON u.id = r.user_id
    INNER JOIN  Role_Names AS rn  ON rn.rn_id = r.role_id

Tip: Many:many mapping tables (your Roles ) are typically named by the the two things it relates. So I suggest User_Roles . Then the 3rd table can be simply Roles . That leads to

SELECT  Users.fname, Role_Names.role_name
    FROM        Users AS u
    INNER JOIN  User_Roles AS ur ON u.id = ur.user_id
    INNER JOIN  Roles      AS r  ON r.rn_id = ur.role_id

You can use DISTINCT like following.

SELECT DISTINCT Users.fname, Role_Names.role_name from Users INNER JOIN 
    Roles on Users.id = Roles.user_id
        INNER JOIN Role_Names
            ON Roles.rn_id = Roles.role_id;

use distinct

with Users as
(
select 1 id, 'Chris' fname,  'Christy' lname
union all
select 2 , 'Brian',  'Bobson' union all
select 3  ,'Jen'  ,  'Sanders'
),Role_Names as
(
select 1 rn_id,  'admin' role_name
union all
select 2 , 'exec' union all
select 3 , 'employee'
) , Roles as
(
select 1 role_id,1 user_id
    union all
     select 1,2 union all
     select 1,3 union all
     select 2  , 3 union all
select 3  , 3 union all
select 3 ,  2
) SELECT distinct Users.fname, Role_Names.role_name 
  from Users left JOIN 
    Roles on Users.id = Roles.user_id
        left JOIN Role_Names
            ON Role_Names.rn_id = Roles.role_id

you missed join in your query

JOIN Role_Names ON Roles.rn_id = Roles.role_id -- here both side you use Roles

Try using below query.

SELECT Users.fname, Role_Names.role_name 
from Roles RIGHT OUTER JOIN 
    Users on Users.id = Roles.user_id
        INNER JOIN Role_Names
            ON Roles_Names.rn_id = Roles.role_id;

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