Shaun
Shaun

Reputation: 546

2 LEFT JOINs in a MySQL Query

I am trying to list all competitions in a table, whether a user has entered each competition, and the total number of entries for each competition.

Here are the tables:

CREATE TABLE `competition` (
`competitionID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` char(255) NOT NULL DEFAULT '',
`description` varchar(750) NOT NULL DEFAULT '',
`startDate` date DEFAULT NULL,
`endDate` date DEFAULT NULL,
`isLive` tinyint(1) NOT NULL,
PRIMARY KEY (`competitionID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `competition` (`competitionID`, `name`, `description`, 
`startDate`, `endDate`, `isLive`)
VALUES
(1,'Win a car','Win a really cool car!','2018-04-01 09:30:27','2019-04-01 09:30:27',1),
(2,'Another competition','Win something even better!','2018-04-01 09:30:27','2019-04-01 09:30:27',1);

CREATE TABLE `competition_entrant` (
`competitionEntrantID` int(11) NOT NULL AUTO_INCREMENT,
`userID` int(11) NOT NULL,
`competitionID` int(11) NOT NULL,
PRIMARY KEY (`competitionEntrantID`),
UNIQUE KEY `userID` (`userID`,`competitionID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `competition_entrant` (`competitionEntrantID`, `userID`, 
`competitionID`)
VALUES
(1,1,1),
(2,1,2),
(3,2,1);

So in this example user with id 1 has entered both competitions and user with id 2 has entered competition with id 1.

Here is my query.

SELECT
`c`.`name`,
COUNT(`ce1`.`userID`) AS 'hasEnteredCompetition',
COUNT(`ce2`.`userID`) AS 'totalEntries'
FROM competition c
LEFT JOIN `competition_entrant` `ce1` ON `c`.`competitionID` = 
`ce1`.`competitionID`
AND `ce1`.`userID` = 2
LEFT JOIN `competition_entrant` `ce2` ON `c`.`competitionID` = 
`ce2`.`competitionID`
GROUP BY (c.competitionID);

The problem is that hasEnteredCompetition is showing the total number of entries rather than just 1 for the user entered i.e. the count for that user.

Can anyone tell me what I'm doing wrong here?

Upvotes: 1

Views: 36

Answers (2)

Tia
Tia

Reputation: 2081

If I understand you correctly (a "expected result" would be nice) you only need to list all competitions, the number of users that entered and if anyone entered at all, right? Then you do not need the second left join, you could go with something like this:

select 
    competition.competitionID, 
    competition.name,
    case when count(competition.competitionID) > 0 THEN 'yes' ELSE 'no' END AS hasEnteredCompetition,
    count(competition.competitionID) AS 'totalEntries'
from competition
left join competition_entrant ON competition.competitionID = competition_entrant.competitionID
group by competitionId, name

Upvotes: 1

Hana
Hana

Reputation: 95

You are joining to the competition_entrant table twice, so the user "2" entry is being pulled twice. You can see it this way:

SELECT C.COMPETITIONID,C.NAME,CE1.USERID,CE1.COMPETITIONID
FROM COMPETITION C
LEFT JOIN COMPETITION_ENTRANT CE1 ON C.COMPETITIONID = CE1.COMPETITIONID AND CE1.USERID = 2
LEFT JOIN COMPETITION_ENTRANT CE2 ON C.COMPETITIONID = CE2.COMPETITIONID


1   Win a car           2       1
2   Another competition null    null        
1   Win a car           2       1

You could add a count distinct to your query like this:

select C.NAME,C.COMPETITIONID,
COUNT(DISTINCT CE1.USERID) as "hasEnteredCompetition",
COUNT(CE2.USERID) as "totalEntries"
from COMPETITION C
left join COMPETITION_ENTRANT CE1 on C.COMPETITIONID = CE1.COMPETITIONIDand CE1.USERID = 2
left join COMPETITION_ENTRANT CE2 on C.COMPETITIONID = CE2.COMPETITIONID
group by (C.NAME,C.COMPETITIONID)

Upvotes: 1

Related Questions