unir subconsulta solo repetidos registros por ordenar group_concat filas fecha espaƱol descendente concatenar agrupar mysql group-by sql-order-by

subconsulta - MySQL ordenar por antes de agrupar por



ordenar por fecha mysql (9)

** Las consultas secundarias pueden tener un impacto negativo en el rendimiento cuando se usan con grandes conjuntos de datos **

Consulta original

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;

Consulta modificada

SELECT p.post_status, p.post_type, Max(p.post_date), p.post_author FROM wp_posts P WHERE p.post_status = "publish" AND p.post_type = "post" GROUP BY p.post_author ORDER BY p.post_date;

porque estoy usando max en la select clause ==> max(p.post_date) es posible evitar las consultas de sub selección y ordenar por la columna max después del grupo.

Hay muchas preguntas similares que se pueden encontrar aquí, pero no creo que ninguna responda adecuadamente a la pregunta.

Continuaré con la question actual más popular y usaré su ejemplo si eso está bien.

La tarea en este caso es obtener la última publicación de cada autor en la base de datos.

La consulta de ejemplo produce resultados inutilizables, ya que no siempre es la última publicación que se devuelve.

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

La respuesta actual aceptada es

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

Desafortunadamente, esta respuesta es sencilla y equivocada, y en muchos casos produce resultados menos estables que la consulta original.

Mi mejor solución es utilizar una subconsulta del formulario.

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

Mi pregunta es simple entonces: ¿hay que ordenar filas antes de agruparlas sin recurrir a una subconsulta?

Edit : Esta pregunta fue una continuación de otra pregunta y los detalles de mi situación son ligeramente diferentes. Puede (y debe) asumir que también hay un wp_posts.id que es un identificador único para esa publicación en particular.


No. No tiene sentido ordenar los registros antes de agrupar, ya que la agrupación mutará el conjunto de resultados. La forma de subconsulta es la forma preferida. Si esto va demasiado lento, tendría que cambiar el diseño de su tabla, por ejemplo, almacenando el id. De la última publicación para cada autor en una tabla separada, o introducir una columna booleana que indique para cada autor cuál de sus publicaciones es la última. uno.


Para recapitular, la solución estándar utiliza una subconsulta no correlacionada y se ve así:

SELECT x.* FROM my_table x JOIN (SELECT grouping_criteria,MAX(ranking_criterion) max_n FROM my_table GROUP BY grouping_criteria) y ON y.grouping_criteria = x.grouping_criteria AND y.max_n = x.ranking_criterion;

Si está utilizando una versión antigua de MySQL, o un conjunto de datos bastante pequeño, puede usar el siguiente método:

SELECT x.* FROM my_table x LEFT JOIN my_table y ON y.joining_criteria = x.joining_criteria AND y.ranking_criteria < x.ranking_criteria WHERE y.some_non_null_column IS NULL;


Primero, no use * en seleccionar, afecta su rendimiento y obstaculiza el uso del grupo y el orden por. Intenta esta consulta:

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

Cuando no especifica la tabla en ORDER BY, solo el alias, ordenarán el resultado de la selección.


Prueba este. Solo obtén la lista de las últimas fechas de publicación de cada autor . Eso es

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


Solo usa la función max y la función group.

select max(taskhistory.id) as id from taskhistory group by taskhistory.taskid order by taskhistory.datum desc


Su solución hace uso de una extensión a la cláusula GROUP BY que permite agrupar por algunos campos (en este caso, solo post_author ):

GROUP BY wp_posts.post_author

y seleccione columnas no agregadas:

SELECT wp_posts.*

que no se enumeran en el grupo por cláusula, o que no se utilizan en una función agregada (MIN, MAX, COUNT, etc.).

Uso correcto de la extensión a la cláusula GROUP BY

Esto es útil cuando todos los valores de las columnas no agregadas son iguales para cada fila.

Por ejemplo, suponga que tiene una mesa GardensFlowers ( name del jardín, flower que crece en el jardín):

INSERT INTO GardensFlowers VALUES (''Central Park'', ''Magnolia''), (''Hyde Park'', ''Tulip''), (''Gardens By The Bay'', ''Peony''), (''Gardens By The Bay'', ''Cherry Blossom'');

y quieres extraer todas las flores que crecen en un jardín, donde crecen múltiples flores. Luego tienes que usar una subconsulta, por ejemplo, podrías usar esto:

SELECT GardensFlowers.* FROM GardensFlowers WHERE name IN (SELECT name FROM GardensFlowers GROUP BY name HAVING COUNT(DISTINCT flower)>1);

Si necesita extraer todas las flores que son las únicas flores en el jardinero, puede cambiar la condición de HAVING COUNT(DISTINCT flower)=1 a HAVING COUNT(DISTINCT flower)=1 , pero MySql también le permite usar esto:

SELECT GardensFlowers.* FROM GardensFlowers GROUP BY name HAVING COUNT(DISTINCT flower)=1;

No hay subconsulta, ni SQL estándar, sino más simple.

Uso incorrecto de la extensión a la cláusula GROUP BY

Pero, ¿qué sucede si SELECCIONA columnas no agregadas que no son iguales para cada fila? ¿Cuál es el valor que MySQL elige para esa columna?

Parece que MySql siempre elige el primer valor que encuentra.

Para asegurarse de que el primer valor que encuentra sea exactamente el valor que desea, debe aplicar un GROUP BY a una consulta ordenada, de ahí la necesidad de usar una subconsulta. No puedes hacerlo de otra manera.

Dado el supuesto de que MySql siempre elige la primera fila que encuentra, usted está clasificando correctamente las filas antes de GROUP BY. Pero, desafortunadamente, si lee la documentación detenidamente, notará que esta suposición no es cierta.

Al seleccionar columnas no agregadas que no siempre son iguales, MySql puede elegir cualquier valor, por lo que el valor resultante que realmente muestra es indeterminado .

Veo que este truco para obtener el primer valor de una columna no agregada se usa mucho, y generalmente / casi siempre funciona, lo uso también a veces (a mi propio riesgo). Pero como no está documentado, no puedes confiar en este comportamiento.

Este enlace (¡gracias a ypercube!) GROUP BY ha sido optimizado y muestra una situación en la que la misma consulta arroja resultados diferentes entre MySql y MariaDB, probablemente debido a un motor de optimización diferente.

Entonces, si este truco funciona, es solo una cuestión de suerte.

La respuesta aceptada en la otra pregunta me parece mal:

HAVING wp_posts.post_date = MAX(wp_posts.post_date)

wp_posts.post_date es una columna no agregada, y su valor será oficialmente indeterminado, pero probablemente será la primera post_date encontrada. Pero como el truco GROUP BY se aplica a una tabla desordenada, no está seguro de cuál es la primera fecha post_date la post_date .

Probablemente devolverá las publicaciones que son las únicas publicaciones de un solo autor, pero incluso esto no siempre es cierto.

Una posible solucion

Creo que esta podría ser una posible solución:

SELECT wp_posts.* FROM wp_posts WHERE id IN ( SELECT max(id) FROM wp_posts WHERE (post_author, post_date) = ( SELECT post_author, max(post_date) FROM wp_posts WHERE wp_posts.post_status=''publish'' AND wp_posts.post_type=''post'' GROUP BY post_author ) AND wp_posts.post_status=''publish'' AND wp_posts.post_type=''post'' GROUP BY post_author )

En la consulta interna, devuelvo la fecha de publicación máxima para cada autor. Luego estoy considerando el hecho de que el mismo autor podría tener dos publicaciones al mismo tiempo, por lo que solo obtengo la ID máxima. Y luego estoy devolviendo todas las filas que tienen esos ID máximos. Se podría hacer más rápido usando uniones en lugar de una cláusula IN.

(Si está seguro de que la ID solo aumenta, y si ID1 > ID2 también significa que post_date1 > post_date2 , la consulta podría ser mucho más sencilla, pero no estoy seguro de que este sea el caso).


Usar un ORDER BY una subconsulta no es la mejor solución para este problema.

La mejor solución para obtener el max(post_date) por autor es usar una subconsulta para devolver la fecha máxima y luego unirla a su tabla tanto en el post_author como en la fecha máxima.

La solución debe ser:

SELECT p1.* FROM wp_posts p1 INNER JOIN ( SELECT max(post_date) MaxPostDate, post_author FROM wp_posts WHERE post_status=''publish'' AND post_type=''post'' GROUP BY post_author ) p2 ON p1.post_author = p2.post_author AND p1.post_date = p2.MaxPostDate WHERE p1.post_status=''publish'' AND p1.post_type=''post'' order by p1.post_date desc

Si tiene los siguientes datos de muestra:

CREATE TABLE wp_posts (`id` int, `title` varchar(6), `post_date` datetime, `post_author` varchar(3)) ; INSERT INTO wp_posts (`id`, `title`, `post_date`, `post_author`) VALUES (1, ''Title1'', ''2013-01-01 00:00:00'', ''Jim''), (2, ''Title2'', ''2013-02-01 00:00:00'', ''Jim'') ;

La subconsulta va a devolver la fecha máxima y el autor de:

MaxPostDate | Author 2/1/2013 | Jim

Luego, ya que está uniendo eso de nuevo a la tabla, en ambos valores devolverá los detalles completos de esa publicación.

Ver SQL Fiddle con Demo .

Para ampliar mis comentarios sobre el uso de una subconsulta para obtener con precisión estos datos.

MySQL no lo obliga a GROUP BY cada columna que incluya en la lista SELECT . Como resultado, si solo GROUP BY una columna pero devuelve 10 columnas en total, no hay garantía de que los otros valores de columna que pertenecen al post_author que se devuelve. Si la columna no está en un GROUP BY MySQL, elige qué valor debe devolverse.

El uso de la subconsulta con la función agregada garantizará que el autor y la publicación correctos se devuelvan cada vez.

Como nota al margen, mientras que MySQL le permite usar un ORDER BY una subconsulta y le permite aplicar un GROUP BY no todas las columnas de la lista SELECT este comportamiento no está permitido en otras bases de datos, incluido SQL Server.


Lo que vas a leer es bastante raro, ¡así que no intentes esto en casa!

En SQL en general, la respuesta a su pregunta es NO , pero debido al modo relajado de GROUP BY (mencionado por @bluefeet ), la respuesta es en MySQL.

Supongamos que tiene un índice BTREE en (post_status, post_type, post_author, post_date). ¿Cómo se ve el índice bajo el capó?

(post_status = ''publish'', post_type = ''post'', post_author = ''user A'', post_date = ''2012-12-01'') (post_status = ''publish'', post_type = ''post'', post_author = ''user A'', post_date = ''2012-12-31'') (post_status = ''publish'', post_type = ''post'', post_author = ''user B'', post_date = ''2012-10-01'') (post_status = ''publish'', post_type = '' post '', post_author ='' usuario B '', post_date ='' 2012-12-01 '')

Es decir, los datos están ordenados por todos esos campos en orden ascendente.

Cuando está haciendo un GROUP BY por defecto, ordena los datos por el campo de agrupación ( post_author , en nuestro caso; post_status, post_type son requeridos por la cláusula WHERE ) y si hay un índice coincidente, toma los datos de cada primer registro en forma ascendente orden. Esa es la consulta que obtendrá lo siguiente (la primera publicación para cada usuario):

(post_status = ''publish'', post_type = ''post'', post_author = ''user A'', post_date = ''2012-12-01'') (post_status = ''publish'', post_type = ''post'', post_author = ''user B'', post_date = ''2012-10-01'')

Pero GROUP BY en MySQL te permite especificar el orden explícitamente. Y cuando solicite post_user en orden descendente, recorrerá nuestro índice en el orden opuesto, aún tomando el primer registro para cada grupo que sea el último.

Es decir

... WHERE wp_posts.post_status=''publish'' AND wp_posts.post_type=''post'' GROUP BY wp_posts.post_author DESC

nos dará

(post_status = ''publish'', post_type = ''post'', post_author = ''user B'', post_date = ''2012-12-01'') (post_status = ''publish'', post_type = ''post'', post_author = ''user A'', post_date = ''2012-12-31'')

Ahora, cuando ordena los resultados de la agrupación por post_date, obtiene los datos que desea.

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

NB :

Esto no es lo que recomendaría para esta consulta en particular. En este caso, usaría una versión ligeramente modificada de lo que sugiere @bluefeet . Pero esta técnica puede ser muy útil. Eche un vistazo a mi respuesta aquí: Recuperar el último registro de cada grupo

Escollos : Las desventajas del enfoque es que

  • el resultado de la consulta depende del índice, que va en contra del espíritu del SQL (los índices solo deberían acelerar las consultas);
  • El índice no sabe nada sobre su influencia en la consulta (usted u otra persona en el futuro puede encontrar que el índice consume demasiado recursos y puede cambiarlo de alguna manera, rompiendo los resultados de la consulta, no solo su rendimiento)
  • Si no entiende cómo funciona la consulta, lo más probable es que olvide la explicación en un mes y la consulta lo confundirá a usted y a sus colegas.

La ventaja es el rendimiento en casos difíciles. En este caso, el rendimiento de la consulta debe ser el mismo que en la consulta de @ bluefeet, debido a la cantidad de datos involucrados en la clasificación (todos los datos se cargan en una tabla temporal y luego se ordenan; por cierto, su consulta requiere la (post_status, post_type, post_author, post_date) también.

Lo que yo sugeriría :

Como dije, esas consultas hacen que MySQL pierda tiempo clasificando potencialmente enormes cantidades de datos en una tabla temporal. En caso de que necesite la paginación (es decir, que LIMIT esté involucrado), la mayoría de los datos se descartan. Lo que haría sería minimizar la cantidad de datos ordenados: eso es ordenar y limitar un mínimo de datos en la subconsulta y luego volver a unir la tabla completa.

SELECT * FROM wp_posts INNER JOIN ( SELECT max(post_date) post_date, post_author FROM wp_posts WHERE post_status=''publish'' AND post_type=''post'' GROUP BY post_author ORDER BY post_date DESC -- LIMIT GOES HERE ) p2 USING (post_author, post_date) WHERE post_status=''publish'' AND post_type=''post'';

La misma consulta utilizando el enfoque descrito anteriormente:

SELECT * FROM ( SELECT post_id FROM wp_posts WHERE post_status=''publish'' AND post_type=''post'' GROUP BY post_author DESC ORDER BY post_date DESC -- LIMIT GOES HERE ) as ids JOIN wp_posts USING (post_id);

Todas esas consultas con sus planes de ejecución en SQLFiddle .