I’ve got a posts table and a postmeta table which contains meta_key and meta_value columns. I’ve included a simplified table structure below (with some demo data).
CREATE TABLE `posts` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(200) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
INSERT INTO `posts` (`id`, `title`) VALUES
(1,'First post'),
(2,'Second post'),
(3,'Third post'),
(4,'Fourth post');
CREATE TABLE `postmeta` (
`meta_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`post_id` int(11) NOT NULL,
`meta_key` varchar(200) NOT NULL DEFAULT '',
`meta_value` text NOT NULL,
PRIMARY KEY (`meta_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
INSERT INTO `postmeta` (`meta_id`, `post_id`, `meta_key`, `meta_value`) VALUES
(1,1,'rating','80'),
(2,1,'total_votes','500'),
(3,2,'rating','80'),
(4,2,'total_votes','501'),
(5,3,'rating','95'),
(6,3,'total_votes','200');
The posts need to be ordered by rating. Post without any rating need to be included too, hence the LEFT JOIN. No problem:
SELECT *
FROM posts p
LEFT JOIN postmeta m ON p.id = m.post_id AND m.meta_key = 'rating'
ORDER BY m.meta_value DESC
However, for posts with the same rating, I’d like to further order them by the total vote count which is stored in another row in the postmeta table. In the example above, the first and second post have a rating of 80 but since the second post has more votes, it should be ordered before the first post. How would you pull that off in a single query?
SQL Fiddle Example
Output: