MySQL Query - последние записи на группу

Я пытаюсь выбрать самые последние записи для каждой группы в таблице.

Скажем, у меня есть таблица «blog_posts», в которой есть столбец для «id» (все уникальные, с автоматическим увеличением), «post_cat», который может быть значениями «category1», «category2» или «category3», и столбец «publish_status», который могут быть значениями «онлайн» или «офлайн».

Как я могу выбрать самые последние записи для каждой категории?

У меня сейчас есть следующее, но мне кажется, что он выбирается случайным образом:

select * FROM `blog_posts` WHERE (publish_status = 'online') GROUP BY post_cat ORDER BY id DESC LIMIT 10

person Jay    schedule 09.02.2011    source источник
comment
Это своего рода выбор случайным образом, поскольку поведение выбора столбцов, которые не являются частью предложения GROUP BY при использовании GROUP BY ... не определено. Согласно руководству по MySQL.   -  person Dan Grossman    schedule 09.02.2011
comment
Дубликат: stackoverflow.com/questions/2129693/   -  person Dan Grossman    schedule 09.02.2011
comment
см. объяснитьсяextended.com/2010/03/ 18 /   -  person Haim Evgi    schedule 09.02.2011


Ответы (3)


Я бы сделал это очень простым и использовал триггер для поддержания last_post_id в таблице категорий, чтобы вы могли легко присоединиться к таблице сообщений - что-то вроде этого:

Простой запрос

select
 pc.cat_id,
 pc.name,
 u.username,
 bp.*
from
 post_category pc
inner join blog_post bp on pc.last_post_id = bp.post_id
inner join users u on bp.user_id = u.user_id
order by
 pc.cat_id;

+--------+------+----------+---------+---------+---------------------+
| cat_id | name | username | post_id | user_id | post_date           |
+--------+------+----------+---------+---------+---------------------+
|      1 | cat1 | bar      |       3 |       2 | 2011-02-09 12:45:33 |
|      2 | cat2 | BAR      |       5 |       3 | 2011-02-09 12:45:33 |
|      3 | cat3 | f00      |       4 |       1 | 2011-02-09 12:45:33 |
+--------+------+----------+---------+---------+---------------------+

Таблицы

drop table if exists post_category;
create table post_category
(
cat_id smallint unsigned not null auto_increment primary key,
name varchar(255) unique not null,
last_post_id int unsigned null,
key (last_post_id)
)
engine=innodb;

drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
username varbinary(32) unique not null
)
engine=innodb;

drop table if exists blog_post;
create table blog_post
(
post_id int unsigned not null auto_increment primary key,
user_id int unsigned not null,
post_date datetime not null,
key (post_date, user_id)
)
engine=innodb;

drop table if exists blog_post_category;
create table blog_post_category
(
cat_id smallint unsigned not null,
post_id int unsigned not null,
primary key (cat_id, post_id)
)
engine=innodb;

Триггеры

delimiter #

create trigger blog_post_before_ins_trig before insert on blog_post
for each row
begin
  set new.post_date = now();
end#

create trigger blog_post_category_before_ins_trig before insert on blog_post_category
for each row
begin
  update post_category set last_post_id = new.post_id where cat_id = new.cat_id;
end#

delimiter ;

Данные испытаний

insert into post_category (name) values ('cat1'),('cat2'),('cat3'),('cat4');
insert into users (username) values ('f00'),('bar'),('BAR'),('alpha'),('beta');

insert into blog_post (user_id) values (1),(1),(2),(1),(3);
insert into blog_post_category (cat_id, post_id) values
(1,1),(1,3),
(2,1),(2,5),
(3,1),(3,3),(3,4);

Надеюсь это поможет :)

person Jon Black    schedule 09.02.2011

Нет действительно простого способа сделать это ...

http://www.artfulsoftware.com/infotree/queries.php#104

http://planet.mysql.com/entry/?id=26926

person Dan Grossman    schedule 09.02.2011
comment
Я пробовал это, но все равно возвращает тот же результат: выберите f.id, f.post_date, f.post_content, f.post_title, f.post_cat из (выберите id, post_date, post_content, post_title, post_cat, max (id) как max_id из группы blog_posts от post_cat) как x внутреннего соединения blog_posts как f на f.post_cat = x.post_cat и f.id = x.id; - person Jay; 09.02.2011

Если у вас всего три категории, вы можете просто сделать отдельные запросы и взять объединение:

(SELECT * FROM `blog_posts` WHERE `publish_status` = 'online' AND `post_cat`='category1' ORDER BY `id` DESC LIMIT 10) UNION
(SELECT * FROM `blog_posts` WHERE `publish_status` = 'online' AND `post_cat`='category2' ORDER BY `id` DESC LIMIT 10) UNION
(SELECT * FROM `blog_posts` WHERE `publish_status` = 'online' AND `post_cat`='category3' ORDER BY `id` DESC LIMIT 10)

Вы можете даже пересортировать все это в конце. Всего 30 рядов!

SELECT * FROM (
    (SELECT * FROM `blog_posts` WHERE `publish_status` = 'online' AND `post_cat`='category1' ORDER BY `id` DESC LIMIT 10) UNION
    (SELECT * FROM `blog_posts` WHERE `publish_status` = 'online' AND `post_cat`='category2' ORDER BY `id` DESC LIMIT 10) UNION
    (SELECT * FROM `blog_posts` WHERE `publish_status` = 'online' AND `post_cat`='category3' ORDER BY `id` DESC LIMIT 10)
) `monster` ORDER BY `id` DESC
person awm    schedule 09.02.2011