Reputation: 288
I've read the examples, but cannot get it to work for my example.
I have a table 'player' with columns 'pid' and 'name' and a table 'card' with columns 'pid', 'points'.
There are multiple card records to a player record.
How can I query the top 5 records per player?
This query returns eveything I need, but doesn't limit to 5 records per name.
SELECT p.pid, p.name, c.points as lp
FROM player as p, card as c
WHERE p.pid=c.pid
ORDER BY p.name, lp DESC
Upvotes: 1
Views: 109
Reputation: 108380
MySQL does not support the "analytic" type function necessary to return the specified resultset. We can emulate the function by making use of MySQL "user variables".
SELECT IF(@prev_name = p.name,@n:=@n+1,@n:=1) AS seq
, @prev_name := p.name AS name
, c.points as lp
FROM player as p
JOIN card as c
ON c.pid = p.pid
JOIN (SELECT @n := 0, @prev_name := NULL) i
HAVING seq <= 5
ORDER BY p.name, lp DESC
Note that the resultset from this statement differs from your original statement, in that it returns an extra column "seq". This column will return values of 1,2,3,etc. indicating whether this was the "first", "second", "third", etc. row for a particular p.name.
The expression used to derive this is basically checking whether the value of p.name on the current row matches the value from the previous row. If it matches, we add a 1; if it doesn't match, then we reset to zero.
The query will actually generate a result set for all rows for each p.name; the HAVING
clause will restrict the rows that are actually returned to the client.
Upvotes: 1
Reputation: 247670
You can use variables to assign a rank to each user:
select pid, name, lp
from
(
SELECT pid,
name,
points as lp,
@prev := @curr,
@curr := name,
@rank := IF(@prev = @curr, @rank+1, 1) AS rank
FROM
(
select p.pid, name, points
FROM player as p
INNER JOIN card as c
ON p.pid=c.pid
) src, (SELECT @curr := null, @prev := null, @rank := 1) r
ORDER BY name, points desc
) src
where rank <= 5
order by name, lp DESC;
Upvotes: 2