简体   繁体   中英

Using the right MYSQL JOIN

I'm trying to get all the data from the match table, along with the currently signed up gamers of each type, experienced or not.

Gamers

(PK)Gamer_Id
Gamer_firstName,
Gamer_lastName,
Gamer experience(Y/N) 

Gamer_matches

(PK)FK GamerId,
(PK)FK MatchId,
Gamer_score

Match

(PK)Match_Id,
ExperiencedGamers_needed,
InExperiencedGamers_needed

I've tried this query along with many others but it doesn't work, is it a bad join?

SELECT M.MatchId,M.ExperiencedGamers_needed,M.InExperiencedGamers_needed,
(SELECT COUNT(GM.GamerId) 
FROM Gamers G, Gamers_matches GM
WHERE G.GamerId = GM.GamerId
AND G.experience = "Y"
AND GM.MatchId = M.MatchId 
GROUP BY GM.MatchId)AS ExpertsSignedUp,

(SELECT COUNT(GM.GamerId)
FROM Gamers G, Gamers_matches GM
WHERE G.GamerId = GM.GamerId
AND G.experience = "N"
AND GM.MatchId = M.MatchId
GROUP BY GM.MatchId) AS NovicesSignedUp

FROM MATCHES M

What you've written is called a correlated subquery which forces SQL to re-execute the subquery for each row fetched from Matches. It can be made to work, but it's pretty inefficient. In some complex queries it may be necessary, but not in this case.

I would solve this query this way:

SELECT M.MatchId, M.ExperiencedGamers_needed,M.InExperiencedGamers_needed,
  SUM(G.experience = 'Y') AS ExpertsSignedUp,
  SUM(G.experience = 'N') AS NovicesSignedUp
FROM MATCHES M
LEFT OUTER JOIN (Gamer_matches GM
    INNER JOIN Gamers G ON G.GamerId = GM.GamerId)
  ON M.MatchId = GM.MatchId
GROUP BY M.MatchId;

Here it outputs only one row per Match because of the GROUP BY at the end.

There's no subquery to re-execute many times, it's just joining Matches to the respective rows in the other tables once. But I use an outer join in case a Match has zero players of eithe type signed up.

Then instead of using COUNT() I use a trick of MySQL and use SUM() with a boolean expression inside the SUM() function. Boolean expressions in MySQL always return 0 or 1. The SUM() of these is the same as the COUNT() where the expression returns true. This way I can get the "count" of both experts and novices only scanning the Gamers table once.


PS MySQL is working in a non-standard way to return 0 or 1 from a boolean expression. Standard ANSI SQL does not support this, nor do many other brands of RDBMS. Standardly, a boolean expression returns a boolean, not an integer.

But you can use a more verbose expression if you need to write standard SQL for portability:

SUM(CASE G.experience WHEN 'Y' THEN 1 WHEN 'N' THEN 0 END) AS ExpertsSignedUp

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