2011-02-28 15 views
46

Necesito encontrar la última publicación para cada autor y luego agrupar los resultados, de modo que solo una última publicación para cada autor.Orden de MySQL antes del grupo por

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 

Esta es la agrupación correctamente la salida, así que solo me dan un post por autor, pero es ordenar los resultados después de que han sido agrupados y no antes de que hayan sido seleccionados.

+4

La forma más rápida de hacerlo es con una consulta interna [ 'code'] (SELECT wp_posts . * FROM (SELECCIONAR * FROM wp_posts ORDER BY wp_post.post_date DESC) como wp_posts WHERE wp_posts.post_status = 'publicar' Y wp_posts.pos t_type = 'post' GROUP BY wp_posts.post_author;) Tal vez no es muy eficiente, pero funciona. – Milos

+1

No creo que la respuesta aceptada para esta pregunta sea correcta y he continuado la pregunta aquí http://stackoverflow.com/questions/14770671/mysql-order-by-before-group-by –

+0

@RobForrest Hey, Me complace actualizar la respuesta seleccionada :) Hace unos años, pregunté esto, así que si hay una manera mejor de alegrarme de señalar a la gente – Tom

Respuesta

22

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


EDITAR:

Después de algunos comentarios, he decidido agregar más información.

La empresa en la que estoy trabajando también utiliza Postgres y especialmente SQL Server. Estas bases de datos no permiten tales consultas. Entonces sé que hay otra forma de hacerlo (escribo una solución a continuación). También debe saber qué hacer si no agrupa por todas las columnas tratadas en la proyección o usa funciones agregadas. De lo contrario, déjalo estar!

Elegí la solución anterior, porque es una pregunta específica. Tom quiere obtener la publicación reciente de cada autor en un sitio de wordpress. En mi opinión, es insignificante para el análisis si un autor hace más de una publicación por segundo. Wordpress incluso debería prohibirlo mediante su detección de doble correo no deseado. Sé por experiencia personal que hay un beneficio realmente significativo en el desempeño haciendo un grupo tan sucio con MySQL. Pero si sabes lo que haces, ¡entonces puedes hacerlo! Tengo grupos tan sucios en aplicaciones de las que soy profesionalmente responsable. Aquí tengo tablas con algunas filas de mio que necesitan 5-15 en lugar de 100 ++ segundos.

Puede ser útil sobre algunos de los pros y contras: 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 

Pero si aquí es más que un puesto por segundo para un autor que obtendrá más de una fila y no es la única últimos uno.

Ahora puede hacer girar la rueda nuevamente y obtener la publicación con la Id más alta. Incluso aquí, al menos, no está garantizado que realmente consigas el último.

+1

¿Soy solo yo o usar MAX() en una cláusula HAVING no funciona? Lo intenté y obtuve un error de 'Uso no válido de la función agregada'. ¿Qué estoy haciendo mal? – Sophivorus

+7

No es solo usted; No creo que esta respuesta tenga sentido. No obtengo un error, pero me da solo una fila, la más alta del conjunto, en lugar de para cada grupo, lo que tiene sentido, ya que HAVING, como ORDER, se procesa después de que el conjunto de filas ya está construido. – LinusR

+1

MySQL devuelve solo una fila. Otro DBMS implementa el estándar SQL más estricto. Si desea obtener un agregado estricto real, debe agrupar todas las columnas tratadas en la proyección o usar funciones agregadas. – edze

5

no importa si ordena antes o después de la declaración de grupo, porque el orden significa solo que 213 pasa a 123 o 321 y no más. group by toma solo ALGUNA entrada por columna, no solo la última. Considero que el trabajo con subselects aquí como

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

¡Me ha ayudado! ¡¡Gracias!! – rAjA

14

No estoy seguro si entiendo su requerimiento correcta pero siguiente declaración interno obtiene la lista de la última post_date para cada autor y se une a ellos volver a la tabla de wp_posts para obtener un registro completo .

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

Esto funcionó para mí, pero solo después de que agregué un 'ORDER BY' adicional a' SELECT' en 'INNER JOIN' (antes de eso, no devolvía necesariamente la publicación más reciente de cada autor). – ACJ

4

¿Qué opina de esto ??Parece que funciona para mí

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 

Se me trae todos los autores con el post_date más actualizada ... ¿Se identifica un problema allí ?? No lo hago

+2

Esto no necesariamente traerá de regreso la publicación más reciente. –

+1

No resuelve el problema – helpse

0

Cuando nuestra mesa se hizo grande, también es necesario verificar el rendimiento. He comprobado todas las opciones en las preguntas aquí, con un sistema de PM con un 136K mensajes y una tabla de enlaces con 83K filas.

Cuando solo necesita contar, o solo ID: la solución de Alex es la mejor.

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 

Cuando necesite otros campos, tengo que modificar solución Husky110 (a mi diseño de la tabla - aquí es único ejemplo - no marcada), que en mis tablas 10 veces más rápido que la opción de subconsulta:

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 

Este cambio puede seleccionar más de una publicación (una para el usuario, por ejemplo), y se puede modificar a otras soluciones.

Moshe.

12

Creo que la respuesta de @edze es incorrecta.

En el MySQL manual se puede leer:

MySQL extiende el uso de GROUP BY para que la lista de selección puede hacer referencia a columnas no agregadas no mencionadas en la cláusula GROUP BY. Puede usar esta característica para obtener un mejor rendimiento al evitar la columna innecesaria ordenar y agrupar. Sin embargo, esto es útil principalmente cuando todos los valores en cada columna no agregada no nombrada en GROUP BY son iguales para cada grupo. El servidor puede elegir libremente cualquier valor de cada grupo , de modo que, a menos que sean iguales, los valores elegidos son indeterminados. Además, la selección de valores de cada grupo no puede verse influenciada por la adición de una cláusula ORDER BY. La clasificación del conjunto de resultados se produce después de que se hayan elegido los valores, y ORDEN POR no afecta a los valores que elige el servidor.

Dos grandes referencias:

Lo sentimos, pero no puedo comentar la respuesta @edze debido a mi reputación, por lo que han escrito una nueva respuesta .

+1

La respuesta @Lieven es la correcta. Pero si dos publicaciones del mismo autor tienen la misma fecha, se necesita un GROUP BY final. – aanton

+0

El segundo enlace es realmente útil para comprender. –

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

¡Hola! Por favor, asegúrese de agregar una explicación a su publicación; tener solo un bloque de código como respuesta generalmente no ayuda al solicitante a entender por qué una respuesta es correcta (concedida, esta pregunta fue hecha y respondida hace dos años, ¡así que creo que Tom ya tiene su respuesta!) –

6

Hacer un GROUP BY después de que el ORDER BY envolviendo la consulta con el GRUPO POR así:

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t GROUP BY t.author 
+0

muy ineficiente , y puede ser reescrito fácilmente por el optimizador de MySQL – newtover

+1

Me decidí por esto porque realmente funcionó y corrió lo suficientemente rápido (menos de 2 segundos en mi base de datos). @newtover Me gustaría encontrar una solución que sea más eficiente, pero he intentado con muchas otras sugerencias y no puedo obtener ninguna de ellas para devolver exactamente lo que necesito (ya que tengo más complejas cláusulas SELECT y WHERE). ¿Puedo tomar mi consulta compleja y pegarla en un "optimizador de MySQL" para solucionarlo? ¿Cómo funcionaría eso? – 11101101b

+0

Lo siento, me perdí tu comentario. En la práctica, el enfoque que describo en [http://stackoverflow.com/questions/1313120/retrieving-the-last-record-in-each-group/8757062#8757062] es muy eficiente, pero requiere una buena comprensión de cómo funciona todo . Si tiene una pregunta sobre una consulta específica que debe optimizarse, puedo ayudarlo con una respuesta específica. Su enfoque es ineficiente porque realmente pone todo en una tabla temporal no indexada y luego realiza una lectura secuencial con un hack específico de MySQL. Es mejor no usar hacks en absoluto o usarlos para soluciones eficientes. – newtover

0

usar el siguiente código ...

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

Gracias, estaba buscando específicamente SQL, no PHP. Esta pregunta ya tiene una buena respuesta. Hay muchas preguntas PHP sin respuesta http://stackoverflow.com/questions/tagged/php?sort=unwithwered – Tom