web-dev-qa-db-fra.com

Ordre MySQL avant regroupement par

Je dois trouver le dernier message pour chaque auteur, puis regrouper les résultats, je n'ai donc qu'un seul dernier message pour chaque auteur.

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

Ceci regroupe correctement la sortie, donc je ne reçois qu'un seul article par auteur, mais il ordonne les résultats après qu'ils ont été regroupés et non avant qu'ils aient été sélectionnés.

49
Tom

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


MODIFIER:

Après quelques commentaires, j'ai décidé d'ajouter quelques informations supplémentaires.

L'entreprise dans laquelle je travaille utilise également Postgres et notamment SQL Server. Ces bases de données ne permettent pas de telles requêtes. Je sais donc qu'il existe une autre façon de procéder (j'écris une solution ci-dessous). Vous devez également savoir ce que vous faites si vous ne regroupez pas toutes les colonnes traitées dans la projection ou si vous utilisez des fonctions d'agrégation. Sinon, que ce soit!

J'ai choisi la solution ci-dessus, car c'est une question spécifique. Tom veut obtenir le post récent de chaque auteur sur un site wordpress. Dans mon esprit, il est négligeable pour l'analyse si un auteur fait plus d'un post par seconde. Wordpress devrait même l'interdire par sa détection de courrier indésirable double. Je sais par expérience personnelle qu'il y a un avantage vraiment significatif dans les performances à faire un groupe aussi sale avec MySQL. Mais si vous savez ce que vous faites, alors vous je peux faire ça! J'ai de tels groupes sales dans les applications dont je suis professionnellement responsable. Ici, j'ai des tables avec quelques mio lignes qui nécessitent 5-15s au lieu de 100 ++ secondes.

Peut être utile sur certains avantages et inconvénients: 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

Mais s'il y a plus d'un article par seconde pour un auteur, vous obtiendrez plus d'une ligne et non le seul le dernier.

Maintenant, vous pouvez à nouveau faire tourner la roue et obtenir le message avec le plus haut Id. Même ici, il n'est au moins pas garanti que vous obtenez vraiment le dernier.

22
edze

Je ne sais pas si je comprends bien votre exigence, mais la déclaration interne suivante obtient la liste de la dernière post_date pour chaque auteur et les joint à la table wp_posts pour obtenir un enregistrement complet.

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
14
Lieven Keersmaekers

Je pense que la réponse @edze est fausse.

Dans le manuel MySQL vous pouvez lire:

MySQL étend l'utilisation de GROUP BY afin que la liste de sélection puisse faire référence à des colonnes non agrégées non nommées dans la clause GROUP BY. Vous pouvez utiliser cette fonctionnalité pour obtenir de meilleures performances en évitant le tri et le regroupement inutiles des colonnes. Toutefois, cela est utile principalement lorsque toutes les valeurs de chaque colonne non agrégée non nommées dans GROUP BY sont les mêmes pour chaque groupe. Le serveur est libre de choisir n'importe quelle valeur dans chaque groupe, donc à moins qu'elles ne soient identiques, les valeurs choisies sont indéterminées. De plus, la sélection des valeurs de chaque groupe ne peut pas être influencée par l'ajout d'une clause ORDER BY. Le tri de l'ensemble de résultats se produit une fois les valeurs choisies et ORDER BY n'affecte pas les valeurs choisies par le serveur.

Deux grandes références:

Désolé, mais je ne peux pas commenter la réponse @edze en raison de ma réputation, j'ai donc écrit une nouvelle réponse.

12
aanton

Faites un GROUP BY après le ORDER BY en encapsulant votre requête avec le GROUP BY comme ceci:

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t GROUP BY t.author
6
11101101b

peu importe si vous commandez avant ou après la déclaration de groupe, car l'ordre signifie seulement que 213 va à 123 ou 321 et pas plus. group by ne prend que QUELQUES entrées par colonne, pas seulement la dernière. Je considère que vous travaillez avec des sous-sélections comme

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 = ... )
5
Husky110

Que penses-tu de cela?? Semble travailler pour moi

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

Cela m'apporte tous les auteurs avec la post_date la plus récente ... Identifiez-vous un problème là-bas ?? Je ne

4
Alex
    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 
1
Mhd Jazaery

Lorsque notre table est devenue grande, les performances doivent également être vérifiées. J'ai vérifié toutes les options dans les questions ici, avec un système PM avec 136K messages et une table de liens avec 83K lignes.

Lorsque vous avez seulement besoin de compter, ou seulement d'ID - la solution d'Alex est la meilleure.

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

Lorsque vous avez besoin d'autres champs, je dois modifier la solution Husky110 (à la conception de ma table - ici, c'est seulement un exemple - non cochée), cela dans mes tables 10 fois plus vite que l'option de sous-requête:

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

Cette modification peut sélectionner plusieurs publications (une pour l'utilisateur, par exemple) et peut être modifiée pour d'autres solutions.

Moshe.

0
Moshe L

Utilisez le code ci-dessous ...

<?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
Kausha Mehta

ICI une réponse simple de 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

ça a fait des merveilles pour moi

0
Black Bronco