ASLSW
ASLSW

Reputation: 53

MySQL: Joins with inner WHERE clauses

[EDIT]

I have now discovered the flaw in this approach. It works well when there is a crew member defined for every position, but completely skips the rows where some crew positions are not filled in.

This is undesirable, only from the perspective that every crew must have a crew leader and a driver, but every other position after that could be empty.

Any thoughts on how to do that? Reading up, it looks like I might have to simulate some sort of full outer join.

[ORIGINAL]

My database has a table for users (called ign_users):

-----------------------------------
¦ user_id ¦ RealName  ¦ surname   ¦
-----------------------------------
¦ 1       ¦ Alpha     ¦ Smith     ¦
-----------------------------------
¦ 2       ¦ Bravo     ¦ Jones     ¦
-----------------------------------
¦ 3       ¦ Charlie   ¦ Brown     ¦
-----------------------------------
¦ 4       ¦ Delta     ¦ White     ¦
-----------------------------------

I have created a new table to create crews (called as_crew):

------------------------------------------------
¦ name  ¦ crew_leader ¦ driver ¦ crew3 ¦ crew4 ¦
------------------------------------------------
¦ A     ¦ 1           ¦ 2      ¦ 3     ¦ 4     ¦
------------------------------------------------
¦ B     ¦ 2           ¦ 4      ¦ 1     ¦ 2     ¦
------------------------------------------------

What I want to be able to do is join the two so that I get the full name (ie. RealName and surname) for each person on the crew.

I can do this one person at a time. For example, the following will return the full name of the crew leader:

SELECT c.name, CONCAT(u.RealName, ' ', surname)
FROM as_crew c, ign_users u
WHERE c.crew_leader=u.user_id

However, I get errors when I try to join this together with another query, eg:

SELECT c.name, CONCAT(u.RealName, ' ', surname)
FROM as_crew c, ign_users u
WHERE c.crew_leader=u.user_id
JOIN
  (SELECT c.name, CONCAT(u.RealName, ' ', surname)
   FROM as_crew c, ign_users u
   WHERE c.DRIVER=u.user_id) AS t
ON c.name=t.name

I think this is due to the WHERE clauses, but I can't figure out how to get this result if I simply remvoe them from inside the SELECT statements and put them on the outside.

For crew3 and crew4 (and others - they go up to crew8), I just want to concatenate the crew together into one result.

Thanks.

Upvotes: 0

Views: 457

Answers (3)

DRapp
DRapp

Reputation: 48139

First, I would try to normalize the data to one row per crew. From THAT, do your join... I've added extra columns in the final output to see how/where the records come from that you can ultimately strip out.

If you want only a specific Crew, Just add the same "WHERE" clause to each "SELECT/FROM" as its breaking down into individual rows... as I've commented with { } below

select
      PreQuery.Name,
      PreQuery.CrewPosition,
      PreQuery.PersonID,
      CONCAT(u.RealName, ' ', U.surname) as  PersonsName
   from
      ( select  c.Name, 
                "Crew Leader " as CrewPosition,
                c.Crew_Leader as PersonID
           from as_crew c
           { SPECIFIC WHERE CLAUSE }
        union 
        select  c.Name, 
                "Driver      " as CrewPosition,
                c.Driver as PersonID
           from as_crew c
           { SPECIFIC WHERE CLAUSE }
        union 
        select  c.Name, 
                "Crew3       " as CrewPosition,
                c.Crew3 as PersonID
           from as_crew c
           { SPECIFIC WHERE CLAUSE }
        union 
        select  c.Name, 
                "Crew4       " as CrewPosition,
                c.Crew4 as PersonID
           from as_crew c 
           { SPECIFIC WHERE CLAUSE }  ) PreQuery

      JOIN ign_users u
         on PreQuery.PersonID = u.User_ID

Here's a solution to get all people on a single row... Revised per comment feedback.

select
      c.Name,
      CONCAT(CL.RealName, ' ', CL.surname) as  CrewLeader,
      CONCAT(dr.RealName, ' ', dr.surname) as  Driver,
      CONCAT( CONCAT(c3.RealName, ' ', c3.surname), ', '
              CONCAT(c4.RealName, ' ', c4.surname) as OtherCrew
   from
      as_crew c
         join ign_users CL
            on c.Crew_Leader = CL.User_ID
         join ign_users dr
            on c.Driver = dr.User_ID
         join ign_users c3
            on c.Crew3 = c4.User_ID
         join ign_users c4
            on c.Crew4 = c4.User_ID

Finally... If a given crew does NOT have all members.. such as only a crew leader and driver, but no Crew3 or Crew4, just change those to LEFT JOIN instead of regular JOIN.

Upvotes: 1

Paul Stanley
Paul Stanley

Reputation: 4098

I think you are trying to use the join keyword in the context of union. IE you want to 'join' results to each other.

SELECT c.name, CONCAT( u.RealName, ' ', surname )
FROM as_crew c, ign_users u
WHERE c.crew_leader = u.user_id
UNION ALL
SELECT c.name, CONCAT( u.RealName, ' ', surname )
FROM as_crew c, ign_users u
WHERE c.DRIVER = u.user_id
UNION ALL
SELECT c.name, CONCAT( u.RealName, ' ', surname )
FROM as_crew c, ign_users u
WHERE c.crew3 = u.user_id

and so on.

Edit : I'd make another table for driver numbers pointing at crew numbers, so you can just have a couple of where statements and you don't have to update all your table structures if your crew size changes, for example.

Edit2 : Try this out.

SELECT c.name, GROUP_CONCAT(CONCAT( ' ',u.RealName, ' ', u.surname )) 
FROM as_crew c, ign_users u
WHERE c.driver = u.user_id OR c.crew_leader = u.user_id  
OR c.crew3 = u.user_id 
OR c.crew4 = u.user_id 
OR c.crew5 = u.user_id 
OR c.crew6 = u.user_id 
OR c.crew7 = u.user_id 
OR c.crew8 = u.user_id
GROUP BY c.name

Upvotes: 0

Tudor Constantin
Tudor Constantin

Reputation: 26861

Try with:

SELECT c1.name, CONCAT(u.RealName, ' ', surname)
FROM as_crew c1, ign_users u
JOIN
  ( (SELECT c.name, CONCAT(u.RealName, ' ', surname)
   FROM as_crew c, ign_users u
   WHERE c.DRIVER=u.user_id) AS t
ON c1.name=t.name )
WHERE c1.crew_leader=u.user_id

Do you still get the errors?

Upvotes: 0

Related Questions