MySQL Order перед группировкой по

47

Мне нужно найти последнее сообщение для каждого автора, а затем сгруппировать результаты, чтобы я только один последний пост для каждого автора.

SELECT wp_posts.* FROM wp_posts
        WHERE wp_posts.post_status='publish'
        AND wp_posts.post_type='post'
        GROUP BY wp_posts.post_author           
        ORDER BY wp_posts.post_date DESC

Это правильная группировка вывода, поэтому я получаю только одно сообщение на автора, но он упорядочивает результаты после их сгруппировки и не до того, как они были выбраны.

  • 4
    Самый быстрый способ сделать это с помощью одного внутреннего запроса [ code ] (SELECT wp_posts. * FROM (SELECT * FROM wp_posts ORDER BY wp_post.post_date DESC) как wp_posts, ГДЕ wp_posts.post_status = 'publish' И wp_posts.post_type = 'post' GROUP BY wp_posts.post_author;) Возможно, это не очень эффективно, но это работает.
  • 1
    Я не думаю, что принятый ответ на этот вопрос является правильным и продолжил вопрос здесь stackoverflow.com/questions/14770671/…
Показать ещё 1 комментарий
Теги:
group-by
sql-order-by

10 ответов

23
Лучший ответ

select wp_posts.* from wp_posts
where wp_posts.post_status='publish'and wp_posts.post_type='post'
group by wp_posts.post_author
having wp_posts.post_date = MAX(wp_posts.post_date) /* ONLY THE LAST POST FOR EACH AUTHOR */
order by wp_posts.post_date descдел >


EDIT:

После некоторых комментариев я решил добавить дополнительную информацию.

В компании, в которой я работаю, также используются Postgres и особенно SQL Server. Эти базы данных не позволяют такие запросы. Поэтому я знаю, что есть другой способ сделать это (я пишу ниже). Вы также должны знать, что вы делаете, если вы не группируете все столбцы, обработанные в проекции, или используйте агрегатные функции. Иначе пусть это будет!

Я выбрал решение выше, потому что это конкретный вопрос. Том хочет получить последнее сообщение для каждого автора на сайте Wordpress. На мой взгляд, для анализа пренебрежимо мало, если автор делает более одного сообщения в секунду. Wordpress должен даже запрещать его путем обнаружения спама-двойного сообщения. По личному опыту я знаю, что в производительности есть действительно значительная выгода, когда вы делаете такую ​​грязную группу с помощью MySQL. Но если вы знаете, что делаете, тогда вы можете это сделать! У меня такие грязные группы в приложениях, за которые я профессионально подотчетен. Здесь у меня есть таблицы с несколькими mio-строками, которым требуется 5-15 секунд вместо 100 + секунд.

Может быть полезно о некоторых плюсах и минусах: http://ftp.nchu.edu.tw/MySQL/tech-resources/articles/debunking-group-by-myths.html


SELECT
    wp_posts.*
FROM 
    wp_posts
    JOIN 
    (
        SELECT
            g.post_author
            MAX(g.post_date) AS post_date
        FROM wp_posts as g
        WHERE
            g.post_status='publish'
            AND g.post_type='post'
        GROUP BY g.post_author
    ) as t 
    ON wp_posts.post_author = t.post_author AND wp_posts.post_date = t.post_date

ORDER BY wp_posts.post_date

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

Теперь вы можете снова закрутить колесо и получить сообщение с наивысшим Id. Даже здесь, по крайней мере, не гарантировано, что вы действительно получите последний.

  • 1
    Это только у меня или использование MAX () в предложении HAVING не работает? Я попробовал это и получил ошибку «Неправильное использование агрегатной функции». Что я делаю неправильно?
  • 7
    Это не только ты; Я не думаю, что этот ответ имеет смысл. Я не получаю ошибку, но она дает мне только одну строку, самую высокую во всем наборе, а не для каждой группы - что имеет смысл, так как HAVING, как ORDER, обрабатывается после того, как набор строк уже собран.
Показать ещё 9 комментариев
14

Не уверен, что я правильно понимаю ваше требование, но после внутреннего оператора получает список последнего post_date для каждого автора и присоединяет их обратно с таблицей wp_posts, чтобы получить полную запись.

SELECT  *
FROM    wp_posts wp
        INNER JOIN (
          SELECT  post_author
                  , MAX(post_date) AS post_date
          FROM    wp_posts
          WHERE   post_status = 'publish'
                  AND post_type = 'post'
          GROUP BY
                  post.author
        ) wpmax ON wpmax.post_author = wp.post_author
                   AND wpmax.post_date = wp.post_date
ORDER BY
        wp.post_date DESC
  • 0
    Это сработало для меня, но только после того, как я добавил дополнительный ORDER BY к SELECT в INNER JOIN (до этого он не обязательно возвращал самую последнюю запись от каждого автора).
12

Я думаю, что ответ @edze неверен.

В руководстве MySQL вы можете прочитать:

MySQL расширяет использование GROUP BY, чтобы список выбора мог ссылаться на неагрегированные столбцы, не указанные в предложении GROUP BY. Вы можете использовать эта функция обеспечивает лучшую производительность, избегая ненужного столбца сортировка и группировка. Однако это полезно прежде всего, когда все значения в каждом неагрегированном столбце, не названном в GROUP BY, являются для каждой группы. Сервер может выбирать любое значение из каждого группы, поэтому, если они не совпадают, выбранные значения неопределенный. Кроме того, выбор значений из каждой группы не может зависеть от добавления предложения ORDER BY. Сортировка набор результатов происходит после того, как были выбраны значения, а ORDER BY не влияет на значения, которые выбирает сервер.

Две отличные ссылки:

Извините, но я не могу прокомментировать ответ @edze из-за моей репутации, поэтому я написал новый ответ.

  • 1
    Ответ @Lieven является правильным. Но если два сообщения от одного автора получили одну и ту же дату, необходим окончательный вариант GROUP BY.
  • 0
    Вторая ссылка действительно полезна для понимания.
6

Сделайте GROUP BY после ORDER BY, обернув свой запрос с помощью GROUP BY следующим образом:

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t GROUP BY t.author
  • 0
    очень неэффективно и может быть легко переписано оптимизатором MySQL
  • 1
    Я остановился на этом, потому что он действительно работал и работал достаточно быстро (менее 2 секунд на моей БД). @newtover Я хотел бы найти более эффективное решение, но я пробовал много других предложений, и я не могу заставить ни одно из них вернуть именно то, что мне нужно (так как у меня есть более сложные предложения SELECT и WHERE). Могу ли я взять свой сложный запрос и вставить его в «оптимизатор MySQL», чтобы исправить это? Как это будет работать?
Показать ещё 4 комментария
5

Не имеет значения, заказываете ли вы до или после группового оператора, потому что порядок означает только то, что 213 отправляется на 123 или 321 и не больше. group принимает только НЕКОТОРУЮ запись в столбце, а не только последнюю. Я считаю, что вы работаете с подзапросами здесь, например

SELECT wp_posts.* FROM wp_posts
        WHERE wp_posts.post_status='publish'
        AND wp_posts.post_type='post'
        AND wp_posts.post_date = (Select max(post_date) from wp_posts where author = ... )
  • 0
    Это помогло мне! Спасибо!!
4

Что вы думаете об этом? Кажется, работает для меня

SELECT wp_posts.post_author, MAX(wp_posts.post_date), wp_posts.status, wp_posts.post_type
FROM wp_posts
    WHERE wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
    GROUP BY wp_posts.post_author

Это приносит мне всех авторов с самым обновленным post_date... Вы идентифицируете проблему там? Я не

  • 2
    Это не обязательно вернет самый последний пост.
  • 1
    Это не решает проблему
1
    SELECT wp_posts.*,max(wp_posts.post_date) FROM wp_posts
    WHERE wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
    GROUP BY wp_posts.post_author 
  • 3
    Здравствуйте! Пожалуйста, не забудьте добавить объяснение к вашему сообщению; наличие только блока кода в качестве ответа обычно не помогает спрашивающему понять, почему ответ правильный (да, этот вопрос был задан и дан ответ два года назад, поэтому я считаю, что у Тома уже есть свой ответ!)
0

ЗДЕСЬ простой ответ от http://www.cafewebmaster.com/mysql-order-sort-group

SELECT * FROM 
(
select * from `my_table` order by timestamp desc
) as my_table_tmp

GROUP BY catid
ORDER BY nid desc

это чудеса для меня

0

Используйте приведенный ниже код...

<?php
//get all users, iterate through users, query for one post for the user,
//if there is a post then display the post title, author, content info
$blogusers = get_users_of_blog();
if ($blogusers) {
  foreach ($blogusers as $bloguser) {
    $args = array(
    'author' => $bloguser->user_id,
      'showposts' => 1,
      'caller_get_posts' => 1
    );
    $my_query = new WP_Query($args);
    if( $my_query->have_posts() ) {
      // $user = get_userdata($bloguser->user_id);
      // echo 'This is one post for author with User ID: ' . $user->ID . ' ' . $user-    >user_firstname . ' ' . $user->user_lastname;
      while ($my_query->have_posts()) : $my_query->the_post(); ?>
        <a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?    php the_title_attribute(); ?>"><?php the_title(); ?></a>

        <small><?php the_time('F jS, Y') ?> by <?php the_author_posts_link() ?>     </small><?php
        the_content();
      endwhile;
    }
  }
}
?>
  • 0
    Спасибо, я специально искал SQL, а не PHP. На этот вопрос уже есть хороший ответ. Есть много неотвеченных вопросов по PHP. Stackoverflow.com/questions/tagged/php?sort=unanspted
0

Когда наш стол стал большим, производительность также нужно проверить. Я проверил все параметры в вопросах здесь, с системой PM с 136 Кб сообщениями и таблицей ссылок с 83 К строк.

Когда вам нужно только подсчитать или использовать только ID - решение Alex лучше всего.

SELECT wp_posts.post_author, MAX(wp_posts.post_date), wp_posts.status, wp_posts.post_type
FROM wp_posts
    WHERE wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
    GROUP BY wp_posts.post_author

Если вам нужны другие поля, мне нужно изменить решение Husky110 (для моей таблицы - здесь это только пример - не проверено), что в моих таблицах 10x быстрее, чем опция подзапроса:

SELECT wp_posts.* FROM wp_posts,
    (Select post_id as pid,  max(post_date) maxdate from wp_posts where author = ... group by author order by maxdate  desc limit 4) t
    WHERE wp_posts.post_status='publish'
    AND wp_posts.post_type='post'
    AND wp_posts.post_id = pid

Это изменение может выбрать более одного сообщения (например, для пользователя) и может быть изменено на другие решения.

Моше.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню