tags:

views:

152

answers:

3

I'm looking to see if I can get the results I need with a single query, and my MySQL skills are still in their adolescence over here.

I have 4 tables: shows, artists, venues and tours. A simplified version of my main query right now looks like this:

SELECT * 
     FROM artists AS a, 
          venues AS v, 
          shows AS s 
LEFT JOIN tours AS t ON s.show_tour_id = t.tour_id
    WHERE s.show_artist_id = a.artist_id
      AND s.show_venue_id = v.venue_id
ORDER BY a.artist_name ASC, s.show_date ASC;

What I want to add is a limit on how many shows are returned per artist. I know I could SELECT * FROM artists, and then run a query with a simple LIMIT clause for each returned row, but I figure there must be a more efficient way.

UPDATE: to put this more simply, I want to select up to 5 shows for each artist. I know I could do this (stripping away all irrelevancies):

<?php
    $artists = $db->query("SELECT * FROM artists");
    foreach($artists as $artist) {
        $db->query("SELECT * FROM shows WHERE show_artist_id = $artist->artist_id LIMIT 5");
    }
?>

But it seems wrong to be putting another query within a foreach loop. I'm looking for a way to achieve this within one result set.

+1  A: 

This is the kind of thing stored procedures are for.

Select a list of artists, then loop through that list, adding 5 or fewer shows for each artists to a temp table.

Then, return the temp table.

Chad
I'm not familiar with stored procedures, though since this is for a WordPress plugin, I need to support MySQL 4.0. Looks like stored procedures are a 5.0 addition. Thanks for the idea though, I should learn more about this.
D-Rock
+1  A: 

As a plan-B, if you can't figure the proper SQL statement to use you can read the whole thing into a memory construct (array, class, etc) and loop it that way. If the data is sufficiently small and memory available sufficiently large this would let you do only one query. Not elegant, but may work for you.

Deverill
Not a bad idea: filter and slice up the array. But definitely a plan B.
D-Rock
+1  A: 

Well I hesitate to suggest this because it certainly won't be computationally efficient (see the stored procedures answer for that...) but it will all be in one query like you wanted. I'm also taking some liberties and assuming that you want the 5 most recent shows...hopefully you can modify to your actual requirements.

SELECT * 
 FROM artists AS a, 
      venues AS v, 
      shows AS s 
LEFT JOIN tours AS t ON s.show_tour_id = t.tour_id
WHERE s.show_artist_id = a.artist_id
  AND s.show_venue_id = v.venue_id
  AND s.show_id IN
     (SELECT subS.show_id FROM shows subS 
      WHERE subS.show_artist_id = s.show_artist_id
      ORDER BY subS.show_date DESC
      LIMIT 5)
ORDER BY a.artist_name ASC, s.show_date ASC;
CarlG
I just read your comment that you're requiring MySQL 4. I don't think MySQL 4 had subqueries, so this might not help you. I'll leave it here in case it might help someone else.
CarlG