Возвращать записи после группировки с определенным MAX (полем)

Я ищу по СТОЛЬКО темам, подобным этой, но не могу применить к моему запросу. Это :

SELECT forum_categories.title, COUNT(DISTINCT forum_topics.id) AS total_topics, 
SUM(CASE WHEN forum_messages.original=0 THEN 1 ELSE 0 END) AS total_replies, forum_messages.author, 
MAX(forum_messages.date) AS last_message, SUM(CASE WHEN r.user IS NULL THEN 1 ELSE 0 END) to_view
FROM forum_categories
JOIN forum_topics ON forum_topics.category_id=forum_categories.id 
LEFT OUTER JOIN (SELECT topic, user FROM forum_visits WHERE user='userA') r ON forum_topics.id=r.topic
JOIN forum_messages ON forum_messages.topic_id=forum_topics.id
GROUP BY forum_categories.id 
ORDER BY forum_categories.date

Это работает: проблема только в том, что возвращается только поле forum_messages.date с МАКСИМАЛЬНЫМИ данными; вместо этого я хотел бы вернуть всю строку с этим полем MAX (например, автор-корреспондент).

Итак, что я должен вернуть, короче говоря, это:

  1. название для каждой категории; *(на данный момент это работает)
  2. количество тем для этой категории; (на данный момент это работает)
  3. количество ответов на все темы данной категории; (здесь есть еще одно условие, как видите, счетчик ответов получает сообщение с полем original=0) (на данный момент это работает)
  4. автор/данные последнего сообщения для этой категории (ЗДЕСЬ есть проблема: корректно возвращается только дата, а не автор);
  5. флаг, указывающий, есть ли какая-либо тема, которую userA еще не проверил; (также на данный момент работает: если SUM возвращает что-то большее, чем 0, значит тема не просматривается)
  6. предполагается, что этот запрос будет максимально быстрым, поскольку таблицы могут быть очень большими;

Для деталей, это мои фактические таблицы:

CREATE TABLE IF NOT EXISTS `forum_categories` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `title` varchar(255) NOT NULL,
  `description` varchar(255) NOT NULL,
  `date` datetime NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `forum_topics` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `category_id` int(11) unsigned NOT NULL,
  `title` varchar(255) NOT NULL,
  `author` varchar(255) NOT NULL,
  `date` datetime NOT NULL,
  `view` int(11) unsigned NOT NULL default '0',
  `sticky` tinyint(11) unsigned NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=25 DEFAULT CHARSET=utf8;    

CREATE TABLE IF NOT EXISTS `forum_messages` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `topic_id` int(11) unsigned NOT NULL,
  `author` varchar(255) NOT NULL,
  `message` mediumtext NOT NULL,
  `date` datetime NOT NULL,
  `original` tinyint(11) unsigned NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=29 DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `forum_visits` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `topic` int(11) unsigned NOT NULL,
  `user` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `forum_visits_unique_idx` (`topic`,`user`)
) ENGINE=MyISAM AUTO_INCREMENT=131 DEFAULT CHARSET=utf8;

Надеюсь, что кто-то может мне помочь!


person kwichz    schedule 06.05.2011    source источник
comment
Итак, на основании чего вам нужна строка forum_message с последней датой? То есть последняя дата по теме?   -  person Thomas    schedule 07.05.2011
comment
У меня есть список сообщений для каждой темы, верно? Он должен печатать: заголовок для каждой категории, количество тем для этой категории, количество ответов для всех тем для этой категории (здесь есть еще одно условие, как вы можете видеть, счетчик этих ответов получает сообщение с поданным original=0) и автором/данными последнего сообщения для этой категории... Да, не простой запрос :)   -  person kwichz    schedule 07.05.2011
comment
возможный дубликат проблемы при группировке   -  person Thomas    schedule 07.05.2011
comment
@Thomas - не совсем дубликат, так как счетчики не будут работать в ответе, который получил kwichz   -  person Galz    schedule 07.05.2011


Ответы (2)


Мы можем использовать запрос из вашего предыдущего вопроса, чтобы получить автора сообщения и дату сообщения, и запрос выше, чтобы получить счетчики (темы и ответы) и объединить их вместе:

EDIT: этот запрос работает (проверено). НО он стал немного сложным и имеет 2 подзапроса, поэтому я надеюсь, что кто-то другой опубликует лучший, более простой. Если БД становится очень большой, это может стать вялым.

SELECT forum_categories.title,
COUNT(DISTINCT forum_topics.id) AS total_topics,
SUM(CASE WHEN forum_messages.original=0 THEN 1 ELSE 0 END) AS total_replies,
t2.author, t2.last_message

-- first get the counters per category
FROM forum_categories
JOIN forum_topics ON forum_topics.category_id=forum_categories.id
JOIN forum_messages ON forum_messages.topic_id=forum_topics.id

-- Then join a query to get last message per category
JOIN (SELECT forum_categories.id, forum_messages.author,
     forum_messages.date AS last_message
     FROM forum_categories
     JOIN forum_topics ON forum_topics.category_id=forum_categories.id
     JOIN forum_messages ON forum_messages.topic_id=forum_topics.id
     JOIN (SELECT MAX(m.date) as date, top.category_id
          FROM forum_messages m
          JOIN forum_topics top ON m.topic_id = top.id
          GROUP BY top.category_id) as t
          ON t.category_id = forum_topics.category_id AND t.date = forum_messages.date
          GROUP BY forum_categories.id) t2
     ON t2.id = forum_categories.id

GROUP BY forum_categories.id
person Galz    schedule 07.05.2011
comment
Да... этот запрос должен быть для форума со многими темами :) Это немного безумно... хе-хе - person kwichz; 07.05.2011

Чтобы дополнить текущий вывод недостающими данными, я бы, вероятно, поступил так:

SELECT
  forum_stats.*,   /* just repeat the already pulled columns (expand it if needed) */
  forum_messages.* /* and here you may actually want to be more specific as to
                       what else you would like to pull from forum_messages */
FROM (
  SELECT
    forum_categories.id AS category_id,
    forum_categories.title,
    COUNT(DISTINCT forum_topics.id) AS total_topics, 
    SUM(CASE WHEN forum_messages.original=0 THEN 1 ELSE 0 END) AS total_replies,
    MAX(forum_messages.date) AS last_message,
    SUM(CASE WHEN r.user IS NULL THEN 1 ELSE 0 END) AS to_view,
    forum_categories.date
  FROM forum_categories
    JOIN forum_topics ON forum_topics.category_id=forum_categories.id 
    LEFT OUTER JOIN (
      SELECT topic, user FROM forum_visits WHERE user='userA'
    ) r ON forum_topics.id=r.topic
    JOIN forum_messages ON forum_messages.topic_id=forum_topics.id
  GROUP BY forum_categories.id
) forum_stats
  JOIN forum_topics ON forum_topics.category_id=forum_stats.category_id
  JOIN forum_messages ON forum_messages.topic_id=forum_topics.id
    AND forum_messages.date=forum_stats.last_message
ORDER BY forum_stats.date

Конечно, это предполагает, что forum_messages.date — это не просто дата, а отметка времени и что никакие два сообщения не могут иметь абсолютно одну и ту же отметку времени.

person Andriy M    schedule 07.05.2011
comment
Спасибо за попытку :) Он не находит столбец forum_stats.id?!?! - person kwichz; 07.05.2011
comment
@kwichz: забыл добавить его в подзапрос, извините. Теперь должно быть хорошо (надеюсь). - person Andriy M; 07.05.2011
comment
Ничего... мне иногда показывает автора, иногда другого... и не всегда того, что стоит в строке с максимальной датой :( - person kwichz; 07.05.2011
comment
@kwichz: Еще раз извините, когда я копировал ваш запрос, я упустил тот факт, что он уже содержал столбец forum_messages.author, который, должно быть, вводил вас в заблуждение. Я удалил его сейчас, пожалуйста, попробуйте этот запрос еще раз. Столбец author теперь извлекается только внешним SELECT на основе category_id и last_message из внутреннего SELECT. - person Andriy M; 07.05.2011