There's a couple of approaches you can use.
One is to make use of an aggregate function and a GROUP BY
clause to "collapse" rows with identical values. We'll assume that we'd determine that a player was in more than two matches if there are at least three rows in the matches
table for that player.
(Also, ditch the old-school comma syntax for the join operation, and use the JOIN
keyword instead.)
Current query:
SELECT p.playerno
FROM PLAYERS p
JOIN MATCHES m
ON m.playerno = p.playerno
WHERE p.town = 'Manchester'
Adding a GROUP BY
clause to collapse rows that have the same value for playerno
.
SELECT p.playerno
, COUNT(1)
FROM PLAYERS p
JOIN MATCHES m
ON m.playerno = p.playerno
WHERE p.town = 'Manchester'
GROUP BY p.playerno
ORDER BY p.playerno
The ORDER BY
isn't strictly necessary, but it makes the returned result more deterministic. (Absent an ORDER BY clause, MySQL is free to return the rows in whatever order it chooses.)
The next trick is to reference the result of the aggregate function (COUNT(1)
) in a HAVING
clause. This can't go into the WHERE
clause, because the predicates in the WHERE clause get evaluated as the rows are accessed. We want to apply a predicate after the rows have been accessed, and the result of the aggregate has been determined.
SELECT p.playerno
FROM PLAYERS p
JOIN MATCHES m
ON m.playerno = p.playerno
WHERE p.town = 'Manchester'
GROUP BY p.playerno
HAVING COUNT(1) > 2
ORDER BY p.playerno
This assumes that the value of matchno
isn't duplicated for the same player. That is, there won't be any two rows with the same values of the tuple (playerno,matchno)
.
If we didn't have that guarantee, but we were guaranteed that matchno
was non-null (at least on the rows we want to consider)... to get a count of the unique values of matchno, we could replace the aggregate COUNT(1)
with COUNT(DISTINCT m.matchno)
.
That's an example of just one approach. There are a couple others...
Another approach is to use a unique column (or set of columns), inequality comparisons, and multiple references to the matches
table. And again assuming that we want to consider only unique value of matchno
for a given player to be included in the count...
We can use a join operation, to restrict the rows returned to only those where there is another row in matches
for the player that has a lower value of matchno
.
SELECT p.playerno
FROM players p
JOIN matches m1 ON m1.playerno = p.playerno
JOIN matches m2 ON m2.playerno = p.playerno AND m2.matchno > m1.matchno
JOIN matches m3 ON m3.playerno = p.playerno AND m3.matchno > m2.matchno
WHERE p.town = 'Manchester'
GROUP BY p.playerno
ORDER BY p.playerno
Another approach is to use an EXISTS
predicates, to perform a similar check. Does a there exist a row in matches for the player, where there exists another row in matches for the same player with greater value of matchno, ...
Something like this:
SELECT p.playerno
FROM players p
WHERE p.town = 'Manchester'
AND EXISTS
( SELECT 1
FROM matches m1
WHERE m1.playerno = p.playerno
AND EXISTS
( SELECT 1
FROM matches m2
WHERE m2.player_no = m1.playerno
AND m2.matchno > m1.matchno
AND EXISTS
( SELECT 1
FROM matches m3
WHERE m3.playerno = m2.playerno
AND m3.matchno > m2.matchno
)
)
)
ORDER BY p.playerno