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)
精彩评论