I’m querying against a database to retrieve some information that includes a one to many relationship. Consider:
CREATE TABLE `movies` (
`id` int(10) unsigned NOT NULL auto_increment,
`title` varchar(50) NOT NULL,
`desc` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO `movies` VALUES ('1', 'The Princess Bride', 'A fantastic film of epic adventure, action, and love.');
CREATE TABLE `showtimes` (
`movie_id` int(10) unsigned NOT NULL,
`showtime_id` int(10) unsigned NOT NULL auto_increment,
`starttime` timestamp NOT NULL,
PRIMARY KEY (`movie_id`,`showtime_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `showtimes` VALUES ('1', '1', '2011-09-19 20:00:00'), ('1', '2', '2011-09-19 23:00:00'), ('1', '3', '2011-09-20 13:00:00');
The way I’d like to receive the information is something like this.
$movies[1] = array(
'id' => 1,
'title' => 'The Princess Bride',
'desc' => 'A fantastic film of epic adventure, action, and love.',
'showtimes' => array(
'1' => '2011-09-19 20:00:00',
'2' => '2011-09-19 23:00:00',
'3' => '2011-09-20 13:00:00'));
This seems to be the most sensible way for me to go through the data. If I’m printing all the showtimes for the theatre, I can do something simple like:
foreach($movies as $movie)
{
//pretend there's style stuff here
echo $movie['title'] . "&mdash" . $movie['desc'];
foreach($movie['showtime'] as $time)
{
if ($time > $_SERVER['REQUEST_TIME'])
{
echo $time;
}
}
}
Unfortunately, that’s not what I get back from a standard query. Something like:
SELECT * FROM `movies` INNER JOIN `showtimes` ON `movies`.`id` = `showtimes`.`movie_id`;
Yields:
$movies[1] = array('id' => 1, 'title' => 'The Princess Bride', 'desc' => 'A fantastic film of epic adventure, action, and love.', 'starttime' => '2011-09-19 20:00:00');
$movies[2] = array('id' => 1, 'title' => 'The Princess Bride', 'desc' => 'A fantastic film of epic adventure, action, and love.', 'starttime' => '2011-09-19 23:00:00');
$movies[3] = array('id' => 1, 'title' => 'The Princess Bride', 'desc' => 'A fantastic film of epic adventure, action, and love.', 'starttime' => '2011-09-20 13:00:00');
which isn’t quite what I’m going for. In larger result sets with more data I’m also mildly curious about the effect of returning so much duplicated data (consider wider rows with tens of joins).
I know I can use a construct like GROUP_CONCAT() to append those showtimes together, but I’m left splitting them apart later. For simple things like timestamps it’s easy as I can choose a delimiter that wont appear in that format, if I was splitting reviews for example it would be a bit tougher.
I can do something lame like iterate over all the movies, querying showtimes from within that loop, but there’s no way that will ever be web scale.
I can execute the join in-query, then iterate over those results and append on duplicate primary key, but that seems to lack elegance as well.
The Question
Is there an elegant way to get what I’m looking for? On this particular application I’m using Zend Framework, if it’s built into that (or another framework) that would be pretty keen.
thanks
Do some kind of join (your choice) on the two tables and then loop through the results.