All the post on their last version
On my database, I have to show a preview with all the posts with their last content and I don't really know how to do it.
CREATE TABLE IF NOT EXISTS `posts` (
`id` int(11) NOT NULL auto_increment,
`post_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
`body` text NOT NULL,
`created` date NOT NULL,
PRIMARY KEY  (`id`),
KEY `post_id` (`post_id`)) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
INSERT INTO `posts开发者_开发百科` (`id`, `post_id`, `title`, `body`, `created`) VALUES 
(1, 1, 'hello world', 'this is the first post', '2011-10-10'), 
(2, 2, 'the second post', 'and this is the second post', '2011-10-10'), 
(3, 2, 'second post', 'title is modified, this is a better version', '2011-10-11');
So the result has to be the post with id 1 and 3. The second post, appears twice because there are two versions on different dates. The dates of the posts marks which version is newer.
I need to display the last state of all the post. How can I do that?
This is a Top-N Per Group Problem:
Here is how you would do it:
SELECT A.* FROM (
    SELECT 
        p.*,
        IF( @p <> ID, @n := 1, @n := @n+1 ) AS r, 
        @p := post_id
    FROM
        posts p
    ORDER BY post_id, created DESC
    ) AS A
WHERE r = 1
For more information: http://www.artfulsoftware.com/infotree/queries.php#104
Explanation:
SELECT A.* FROM (
    SELECT 
        p.*,
        IF( 
                @p <> ID,   /* check if this record is a new post_id */
                @n := 1,    /* if it is a new post_id, reset the counter to 1 */
                @n := @n+1  /* other wise, increment the counter */
            ) AS r,
        @p := post_id   /* assign the post_id of this record to @p to use in the IF statement */
    FROM
        posts p
    ORDER BY 
        post_id,     /*first, order by postID so we scan over all versions of posts together */
        created DESC /* then order by createDate DESC so the newest versions of each post are first */
    ) AS A
WHERE r = 1
Sample Results (of the subquery):
id | post_id | title | body | created    | r | @p
1  | 1       | ...   | ...  | 10/10/2011 | 1 | 1
3  | 2       | ...   | ...  | 10/11/2011 | 1 | 2
2  | 2       | ...   | ...  | 10/10/2011 | 2 | 2
How about this? ID is being used to tell which one is newer.
SELECT id, post_id, title, body, created
FROM posts 
WHERE (post_id, id) IN (SELECT post_id, MAX(id) FROM posts GROUP BY post_id)
If you need to use date (what if there are two posts on the same date?)
SELECT id, post_id, title, body, created
FROM posts 
WHERE (post_id, created) IN (SELECT post_id, MAX(created) FROM posts GROUP BY post_id)
 
         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论