Reputation: 19
I've got a mysql table of 'events' with columns for 'category' and 'visited'. There's 3 categories an event can fall under. 'visited' counts how many times the event's page has been visited. I want the top two visited events from each of the 3 categories.
Here is an example table
id category visited
32 1 23
33 2 12
34 3 42
35 1 53
36 2 24
37 3 84
38 1 12
39 2 75
40 3 22
I need to display these rows in this order (id=): 35, 32, 39, 36, 37, 34. The code I have returns only 1 row from each category, and I believe is strictly limited to returning 1 row (I didn't write it.):
$categories=mysql_query("select distinct category from events");
while($row_cat=mysql_fetch_array($categories)){
$row=mysql_fetch_array(mysql_query("select * from events where category='".$row_cat['category']."' order by visited desc"));
echo $row['id'].", ";
}
That code displays: 35, 39, 37,
I feel as though the answer may be extremely simple, yet it is still eluding me. Thanks, in advance, for your help.
Upvotes: 1
Views: 1019
Reputation: 115520
SELECT e.*
FROM
( SELECT DISTINCT category
FROM events
) AS ed
JOIN
events AS e
ON e.category = ed.category
AND e.visited >=
( SELECT visited
FROM events AS ei
WHERE ei.category = ed.category
ORDER BY visited DESC
LIMIT 1 OFFSET 1
)
Upvotes: 0
Reputation: 91017
What about
SELECT category, GROUP_CONCAT(id ORDER BY visited DESC)
FROM events
GROUP BY category
?
For your original code: It is because you only ask for one row.
Your while loop iterates over all categories. For each of them. it issues a query and asks for one row. You'd need 2 nested loop to query everything. So the "purely-MySQL" solution is by far better.
But if you need more than you stated originally, you probably better really do these queries one-by-one by nesting loops PHP-side:
$categories=mysql_query("select distinct category from events");
while($row_cat=mysql_fetch_array($categories)){
$inner_res=mysql_query("select * from events where category='".mysql_real_escape_string($row_cat['category'])."' order by visited desc");
while($inner_row=mysql_fetch_array($inner_res)){
echo $inner_row['id'].", ";
}
}
Upvotes: 1
Reputation: 51655
@glglgl method is really cool +1, also you can use find in set function to refine it and get first 3 events for each category one by row:
select e0.*
from
events e0
inner join
(SELECT category,
GROUP_CONCAT(id ORDER BY visited DESC) as events
FROM events
GROUP BY category) C
on
e0.category = c.category and
find_in_set( e0.event, c.events ) < 3
Be carefull, if you have a lot of events this can run slow.
Disclaimer: not tested.
Upvotes: 1