MySQL group by и max возвращает неправильные строки - PullRequest
8 голосов
/ 29 ноября 2011

У меня есть две таблицы, и я пытаюсь найти «пост» с наибольшим количеством очков в день.

CREATE TABLE IF NOT EXISTS `posts_points` (
  `post_id` int(10) unsigned NOT NULL,
  `comments` smallint(5) unsigned NOT NULL,
  `likes` smallint(5) unsigned NOT NULL,
  `favorites` smallint(5) unsigned NOT NULL,
   PRIMARY KEY (`post_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `posts` (
  `profile_id` int(10) unsigned NOT NULL,
  `post_id` int(10) unsigned NOT NULL,
  `pubdate_utc` datetime NOT NULL,
  PRIMARY KEY (`post_id`),
  KEY `profile_id` (`profile_id`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

Я пробовал запрос ниже.Возвращает правильный результат, но остальные столбцы - это просто случайные строки.Что я делаю не так?

SELECT p.post_id, p.profile_id
   , MAX(t1.score)
   , DATE_FORMAT(t1.pubdate_utc, '%d %b') post_date
   , DATE(t1.pubdate_utc) mydate
FROM
(
   SELECT p.profile_id, p.post_id, p.pubdate_utc
      , (pp.comments + pp.likes + pp.favorites) AS score
   FROM posts p 
   INNER JOIN posts_points pp ON p.post_id = pp.post_id
) t1
INNER JOIN posts p ON t1.post_id = p.post_id
   AND t1.pubdate_utc = p.pubdate_utc
GROUP BY mydate
ORDER BY mydate DESC
LIMIT 18;

Ответы [ 5 ]

2 голосов
/ 01 января 2012

Я постоянно сталкиваюсь с этой проблемой.Когда MySQL запускает агрегатную функцию для любых неагрегированных столбцов, он просто извлекает первые данные, с которыми сталкивается для этой группы, независимо от того, получены они из строки MAX или нет.Итак, вам нужно упорядочить данные во внутреннем запросе так, чтобы максимумы были первыми в своих группах.Посмотрите, работает ли это для вас:

SELECT t.post_id,
       t.profile_id,
       t.score,
       t.pubdate_utc
FROM (SELECT p.profile_id,
             p.post_id,
             p.pubdate_utc,
             (pp.comments + pp.likes + pp.favorites) score
      FROM posts p
      JOIN posts_points pp ON p.post_id = pp.post_id
      WHERE p.pubdate_utc >= DATE_ADD(DATE(NOW()), INTERVAL -17 DAY)
      ORDER BY score DESC
     ) t
GROUP BY DATE(t.pubdate_utc) DESC
;

Обратите внимание, что здесь я не использую функцию MAX.Упорядочение по убыванию оценки, а затем группировка по дате во внешнем запросе увеличит наивысшую оценку по дате.Также обратите внимание, что я поместил предложение WHERE во внутренний запрос.Внутренние запросы, подобные этому (иногда это необходимо), не очень эффективны, поскольку у них нет индексов для оптимизации внешнего запроса, поэтому убедитесь, что ваш внутренний результирующий набор настолько мал, насколько это возможно.Наконец, обратите внимание на дату GROUP BY DATE (t.pubdate_utc).Если бы я не сократил ее до информации только о дате, было бы намного больше 18 результатов, так как тогда также учитывается время.

Правка: изменено на INTERVAL -17 DAY, чтобы вместо этого получалось до 18 результатовиз 19

0 голосов
/ 22 декабря 2011

вы можете увидеть этот запрос. Внутренний запрос сначала извлекает те строки, которые имеют одинаковый post_id в обеих таблицах, чем sum (pp.comments + pp.likes + pp.fabilities) в виде Score. Outer Query - получить максимальный счет и выполнить группу в день мудрый ....

SELECT post_id, profile_id
   , MAX(score)
   , DATE_FORMAT(pubdate_utc, '%d %b') post_date
   , DATE(pubdate_utc) as mydate
FROM
(
   SELECT p.profile_id, p.post_id, p.pubdate_utc
      , (pp.comments + pp.likes + pp.favorites) AS score
   FROM posts p 
   INNER JOIN posts_points pp ON p.post_id = pp.post_id
) 
GROUP BY pubdate_utc
ORDER BY pubdate_utc DESC
0 голосов
/ 29 ноября 2011

немного сложно понять, что вы хотите сделать.

Слова (столбцы (посты, комментарии, избранное) и PK), я понял, что вы обновляете значения, увеличивающиеся, и не делаетзаписывать каждый голос.

Этот выбор возвращает данные из сообщения и счет, упорядочивая больший балл, ограниченный 18.

        SELECT P.post_id,
               P.profile_id,
               (PP.comments + PP.likes + PP.favorites) AS score,
               DATE_FORMAT (P.pubdate_utc, '%d %b') AS post_data,
               DATE (P.pubdate_utc) AS mydate
          FROM posts P
    INNER JOIN posts_points PP
            ON (= P.post_id PP.post_id)
      ORDER BY 3 DESC
         LIMIT 18;

Если вы хотитечтобы выбрать наибольшее количество голосов за день, вы должны записать в эту таблицу разные лайки / фавориты, данные о нуждах (posts_points).

0 голосов
/ 06 декабря 2011

Вау! Tricky. Например, всегда есть возможность галстука для макс.

Приведенное ниже решение создает промежуточный список дневных max_scores, затем получает все сообщения, чьи оценки равны максимальным за их день. Он возвращает связи, поэтому вы можете получить две строки за данный день. Прошу у вас прощения, что я не могу это проверить, поэтому оставьте отзыв, и я уверен, что мы сможем сделать это, чтобы сделать то, что вам нужно.

SELECT p.profile_id, p.post_id, p.pubdate_utc
, DATE_FORMAT(p.pubdate_utc, '%d %b') AS post_date
, DATE(p.pubdate_utc) AS mydate
, (pp.comments + pp.likes + pp.favorites) AS score
FROM posts p 
INNER JOIN posts_points pp ON p.post_id = pp.post_id
INNER JOIN 
(
    SELECT p.pubdate_utc AS max_date, 
    (pp.comments + pp.likes + pp.favorites) AS max_score
    FROM posts p2 
    INNER JOIN posts_points pp2 ON p2.post_id = pp2.post_id
) m ON score = m.max_score
AND mydate = m.max_date
ORDER BY mydate DESC
LIMIT 18;
0 голосов
/ 29 ноября 2011
Column1  Column2
C        d
A        any thing
D        y
B        z  

Если вы упорядочиваете эти данные по Column1, то это выглядит так ... orderby просто упорядочивает первый столбец ....

Column1  Column2
A        any thing
B        z            
C        d
D        y
...