ultimo - sql seleccionar registro mayor fecha
Recuperando el Ășltimo registro en cada grupo-MySQL (21)
¿Hay alguna manera de que podamos usar este método para eliminar duplicados en una tabla? El conjunto de resultados es básicamente una colección de registros únicos, por lo que si pudiéramos eliminar todos los registros que no están en el conjunto de resultados, ¿no tendríamos duplicados? Intenté esto pero mySQL dio un error 1093.
DELETE FROM messages WHERE id NOT IN
(SELECT m1.id
FROM messages m1 LEFT JOIN messages m2
ON (m1.name = m2.name AND m1.id < m2.id)
WHERE m2.id IS NULL)
¿Hay alguna manera de guardar la salida en una variable temporal y luego eliminarla de NOT IN (variable temporal)? @Bill gracias por una solución muy útil.
EDITAR: Creo que encontré la solución:
DROP TABLE IF EXISTS UniqueIDs;
CREATE Temporary table UniqueIDs (id Int(11));
INSERT INTO UniqueIDs
(SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON
(T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields
AND T1.ID < T2.ID)
WHERE T2.ID IS NULL);
DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs);
Hay una tabla de messages
que contiene datos como se muestra a continuación:
Id Name Other_Columns
-------------------------
1 A A_data_1
2 A A_data_2
3 A A_data_3
4 B B_data_1
5 B B_data_2
6 C C_data_1
Si ejecuto una consulta, select * from messages group by name
, obtendré el resultado como:
1 A A_data_1
4 B B_data_1
6 C C_data_1
¿Qué consulta devolverá el siguiente resultado?
3 A A_data_3
5 B B_data_2
6 C C_data_1
Es decir, se debe devolver el último registro de cada grupo.
En la actualidad, esta es la consulta que uso:
SELECT
*
FROM (SELECT
*
FROM messages
ORDER BY id DESC) AS x
GROUP BY name
Pero esto parece altamente ineficiente. ¿Alguna otra forma de lograr el mismo resultado?
Aquí está mi solución:
SELECT
DISTINCT NAME,
MAX(MESSAGES) OVER(PARTITION BY NAME) MESSAGES
FROM MESSAGE;
Aquí hay dos sugerencias. Primero, si mysql admite ROW_NUMBER (), es muy simple:
WITH Ranked AS (
SELECT Id, Name, OtherColumns,
ROW_NUMBER() OVER (
PARTITION BY Name
ORDER BY Id DESC
) AS rk
FROM messages
)
SELECT Id, Name, OtherColumns
FROM messages
WHERE rk = 1;
Supongo que por "último" quiere decir último en el orden de identificación. Si no, cambie la cláusula ORDER BY de la ventana ROW_NUMBER () en consecuencia. Si ROW_NUMBER () no está disponible, esta es otra solución:
En segundo lugar, si no lo hace, a menudo es una buena manera de proceder:
SELECT
Id, Name, OtherColumns
FROM messages
WHERE NOT EXISTS (
SELECT * FROM messages as M2
WHERE M2.Name = messages.Name
AND M2.Id > messages.Id
)
En otras palabras, seleccione los mensajes donde no haya un mensaje de identificación posterior con el mismo nombre.
Claramente hay muchas formas diferentes de obtener los mismos resultados, su pregunta parece ser cuál es una forma eficiente de obtener los últimos resultados en cada grupo en MySQL. Si está trabajando con grandes cantidades de datos y suponiendo que está utilizando InnoDB incluso con las últimas versiones de MySQL (como 5.7.21 y 8.0.4-rc), es posible que no haya una forma eficiente de hacerlo.
A veces necesitamos hacer esto con tablas con más de 60 millones de filas.
Para estos ejemplos, usaré datos con solo alrededor de 1.5 millones de filas donde las consultas necesitarían encontrar resultados para todos los grupos en los datos. En nuestros casos reales, a menudo tendríamos que devolver datos de unos 2.000 grupos (lo que hipotéticamente no requeriría examinar gran parte de los datos).
Usaré las siguientes tablas:
CREATE TABLE temperature(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
groupID INT UNSIGNED NOT NULL,
recordedTimestamp TIMESTAMP NOT NULL,
recordedValue INT NOT NULL,
INDEX groupIndex(groupID, recordedTimestamp),
PRIMARY KEY (id)
);
CREATE TEMPORARY TABLE selected_group(id INT UNSIGNED NOT NULL, PRIMARY KEY(id));
La tabla de temperatura se rellena con aproximadamente 1,5 millones de registros aleatorios y con 100 grupos diferentes. El grupo seleccionado se llena con esos 100 grupos (en nuestros casos, esto normalmente sería menos del 20% para todos los grupos).
Como estos datos son aleatorios, significa que varias filas pueden tener las mismas marcas de tiempo registradas. Lo que queremos es obtener una lista de todos los grupos seleccionados en orden de groupID con la última marca de tiempo registrada para cada grupo, y si el mismo grupo tiene más de una fila coincidente como esa, entonces la última identificación coincidente de esas filas.
Si hipotéticamente MySQL tenía una función last () que devolvía valores de la última fila en una cláusula ORDER BY especial, entonces simplemente podríamos hacer:
SELECT
last(t1.id) AS id,
t1.groupID,
last(t1.recordedTimestamp) AS recordedTimestamp,
last(t1.recordedValue) AS recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.groupID = g.id
ORDER BY t1.recordedTimestamp, t1.id
GROUP BY t1.groupID;
que solo necesitaría examinar unas 100 filas en este caso, ya que no usa ninguna de las funciones normales de GROUP BY. Esto se ejecutaría en 0 segundos y por lo tanto sería altamente eficiente. Tenga en cuenta que normalmente en MySQL veríamos una cláusula ORDER BY después de la cláusula GROUP BY; sin embargo, esta cláusula ORDER BY se usa para determinar la ORDER para la función last (), si estuviera después de GROUP BY, entonces estaría ordenando los GRUPOS. Si no existe una cláusula GROUP BY, los últimos valores serán los mismos en todas las filas devueltas.
Sin embargo, MySQL no tiene esto, así que echemos un vistazo a las diferentes ideas de lo que tiene y probemos que ninguna de ellas es eficiente.
Ejemplo 1
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.id = (
SELECT t2.id
FROM temperature t2
WHERE t2.groupID = g.id
ORDER BY t2.recordedTimestamp DESC, t2.id DESC
LIMIT 1
);
Este examinó 3,009,254 filas y tomó ~ 0,859 segundos en 5.7.21 y ligeramente más largo en 8.0.4-rc.
Ejemplo 2
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM temperature t1
INNER JOIN (
SELECT max(t2.id) AS id
FROM temperature t2
INNER JOIN (
SELECT t3.groupID, max(t3.recordedTimestamp) AS recordedTimestamp
FROM selected_group g
INNER JOIN temperature t3 ON t3.groupID = g.id
GROUP BY t3.groupID
) t4 ON t4.groupID = t2.groupID AND t4.recordedTimestamp = t2.recordedTimestamp
GROUP BY t2.groupID
) t5 ON t5.id = t1.id;
Esto examinó 1,505,331 filas y tomó ~ 1.25 segundos en 5.7.21 y ligeramente más largo en 8.0.4-rc.
Ejemplo 3
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM temperature t1
WHERE t1.id IN (
SELECT max(t2.id) AS id
FROM temperature t2
INNER JOIN (
SELECT t3.groupID, max(t3.recordedTimestamp) AS recordedTimestamp
FROM selected_group g
INNER JOIN temperature t3 ON t3.groupID = g.id
GROUP BY t3.groupID
) t4 ON t4.groupID = t2.groupID AND t4.recordedTimestamp = t2.recordedTimestamp
GROUP BY t2.groupID
)
ORDER BY t1.groupID;
Esto examinó 3,009,685 filas y tomó ~ 1.95 segundos en 5.7.21 y un poco más en 8.0.4-rc
Ejemplo 4
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.id = (
SELECT max(t2.id)
FROM temperature t2
WHERE t2.groupID = g.id AND t2.recordedTimestamp = (
SELECT max(t3.recordedTimestamp)
FROM temperature t3
WHERE t3.groupID = g.id
)
);
Esto examinó 6,137,810 filas y tomó ~ 2.2 segundos en 5.7.21 y ligeramente más largo en 8.0.4-rc
Ejemplo 5
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM (
SELECT
t2.id,
t2.groupID,
t2.recordedTimestamp,
t2.recordedValue,
row_number() OVER (
PARTITION BY t2.groupID ORDER BY t2.recordedTimestamp DESC, t2.id DESC
) AS rowNumber
FROM selected_group g
INNER JOIN temperature t2 ON t2.groupID = g.id
) t1 WHERE t1.rowNumber = 1;
Esto examinó 6,017,808 filas y tomó ~ 4.2 segundos en 8.0.4-rc
Ejemplo 6
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM (
SELECT
last_value(t2.id) OVER w AS id,
t2.groupID,
last_value(t2.recordedTimestamp) OVER w AS recordedTimestamp,
last_value(t2.recordedValue) OVER w AS recordedValue
FROM selected_group g
INNER JOIN temperature t2 ON t2.groupID = g.id
WINDOW w AS (
PARTITION BY t2.groupID
ORDER BY t2.recordedTimestamp, t2.id
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)
) t1
GROUP BY t1.groupID;
Esto examinó 6,017,908 filas y tomó ~ 17.5 segundos en 8.0.4-rc
Ejemplo 7
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.groupID = g.id
LEFT JOIN temperature t2
ON t2.groupID = g.id
AND (
t2.recordedTimestamp > t1.recordedTimestamp
OR (t2.recordedTimestamp = t1.recordedTimestamp AND t2.id > t1.id)
)
WHERE t2.id IS NULL
ORDER BY t1.groupID;
Este estaba tomando para siempre así que tuve que matarlo.
Esta es otra forma de obtener el último registro relacionado utilizando GROUP_CONCAT
con orden by y SUBSTRING_INDEX
para seleccionar uno de los registros de la lista
SELECT
`Id`,
`Name`,
SUBSTRING_INDEX(
GROUP_CONCAT(
`Other_Columns`
ORDER BY `Id` DESC
SEPARATOR ''||''
),
''||'',
1
) Other_Columns
FROM
messages
GROUP BY `Name`
La consulta anterior Other_Columns
todas las Other_Columns
que están en el mismo grupo de Name
y utilizando ORDER BY id DESC
unirá todas las Other_Columns
en un grupo específico en orden descendente con el separador provisto en mi caso que he usado ||
, al usar SUBSTRING_INDEX
sobre esta lista se seleccionará el primero
Demostración de violín
Hola, @Vijay Dev si los mensajes de tu tabla contienen Id, que es una clave primaria de incremento automático, para obtener el último registro de la clave principal que tu consulta debe leer como se muestra a continuación:
SELECT m1.* FROM messages m1 INNER JOIN (SELECT max(Id) as lastmsgId FROM messages GROUP BY Name) m2 ON m1.Id=m2.lastmsgId
La siguiente consulta funcionará bien según su pregunta.
SELECT M1.*
FROM MESSAGES M1,
(
SELECT SUBSTR(Others_data,1,2),MAX(Others_data) AS Max_Others_data
FROM MESSAGES
GROUP BY 1
) M2
WHERE M1.Others_data = M2.Max_Others_data
ORDER BY Others_data;
Llegué a una solución diferente, que es obtener los ID para la última publicación dentro de cada grupo, luego seleccionar de la tabla de mensajes usando el resultado de la primera consulta como el argumento para una construcción WHERE x IN
:
SELECT id, name, other_columns
FROM messages
WHERE id IN (
SELECT MAX(id)
FROM messages
GROUP BY name
);
No sé cómo funciona esto en comparación con algunas de las otras soluciones, pero funcionó espectacularmente para mi mesa con más de 3 millones de filas. (4 segundos de ejecución con más de 1200 resultados)
Esto debería funcionar tanto en MySQL como en SQL Server.
MySQL 8.0 ahora admite funciones de ventanas, como casi todas las implementaciones populares de SQL. Con esta sintaxis estándar, podemos escribir las mejores consultas por grupo:
WITH ranked_messages AS (
SELECT m.*, ROW_NUMBER() OVER (PARTITION BY name ORDER BY id DESC) AS rn
FROM messages AS m
)
SELECT * FROM ranked_messages WHERE rn = 1;
A continuación se muestra la respuesta original que escribí para esta pregunta en 2009:
Escribo la solución de esta manera:
SELECT m1.*
FROM messages m1 LEFT JOIN messages m2
ON (m1.name = m2.name AND m1.id < m2.id)
WHERE m2.id IS NULL;
En cuanto al rendimiento, una solución u otra puede ser mejor, dependiendo de la naturaleza de sus datos. Por lo tanto, debe probar ambas consultas y usar una que sea mejor en su rendimiento dada su base de datos.
Por ejemplo, tengo una copia del volcado de datos de agosto de . Voy a usar eso para la evaluación comparativa. Hay 1,114,357 filas en la tabla de Posts
. Esto se ejecuta en MySQL 5.0.75 en mi Macbook Pro 2.40GHz.
Escribiré una consulta para encontrar la publicación más reciente para un ID de usuario determinado (el mío).
Primero, utilizando la técnica shown por @Eric con GROUP BY
en una subconsulta:
SELECT p1.postid
FROM Posts p1
INNER JOIN (SELECT pi.owneruserid, MAX(pi.postid) AS maxpostid
FROM Posts pi GROUP BY pi.owneruserid) p2
ON (p1.postid = p2.maxpostid)
WHERE p1.owneruserid = 20860;
1 row in set (1 min 17.89 sec)
Incluso el análisis EXPLAIN
lleva más de 16 segundos:
+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 76756 | |
| 1 | PRIMARY | p1 | eq_ref | PRIMARY,PostId,OwnerUserId | PRIMARY | 8 | p2.maxpostid | 1 | Using where |
| 2 | DERIVED | pi | index | NULL | OwnerUserId | 8 | NULL | 1151268 | Using index |
+----+-------------+------------+--------+----------------------------+-------------+---------+--------------+---------+-------------+
3 rows in set (16.09 sec)
Ahora produzca el mismo resultado de la consulta usando mi técnica con LEFT JOIN
:
SELECT p1.postid
FROM Posts p1 LEFT JOIN posts p2
ON (p1.owneruserid = p2.owneruserid AND p1.postid < p2.postid)
WHERE p2.postid IS NULL AND p1.owneruserid = 20860;
1 row in set (0.28 sec)
El análisis de EXPLAIN
muestra que ambas tablas pueden usar sus índices:
+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
| 1 | SIMPLE | p1 | ref | OwnerUserId | OwnerUserId | 8 | const | 1384 | Using index |
| 1 | SIMPLE | p2 | ref | PRIMARY,PostId,OwnerUserId | OwnerUserId | 8 | const | 1384 | Using where; Using index; Not exists |
+----+-------------+-------+------+----------------------------+-------------+---------+-------+------+--------------------------------------+
2 rows in set (0.00 sec)
Aquí está el DDL para mi tabla de Posts
:
CREATE TABLE `posts` (
`PostId` bigint(20) unsigned NOT NULL auto_increment,
`PostTypeId` bigint(20) unsigned NOT NULL,
`AcceptedAnswerId` bigint(20) unsigned default NULL,
`ParentId` bigint(20) unsigned default NULL,
`CreationDate` datetime NOT NULL,
`Score` int(11) NOT NULL default ''0'',
`ViewCount` int(11) NOT NULL default ''0'',
`Body` text NOT NULL,
`OwnerUserId` bigint(20) unsigned NOT NULL,
`OwnerDisplayName` varchar(40) default NULL,
`LastEditorUserId` bigint(20) unsigned default NULL,
`LastEditDate` datetime default NULL,
`LastActivityDate` datetime default NULL,
`Title` varchar(250) NOT NULL default '''',
`Tags` varchar(150) NOT NULL default '''',
`AnswerCount` int(11) NOT NULL default ''0'',
`CommentCount` int(11) NOT NULL default ''0'',
`FavoriteCount` int(11) NOT NULL default ''0'',
`ClosedDate` datetime default NULL,
PRIMARY KEY (`PostId`),
UNIQUE KEY `PostId` (`PostId`),
KEY `PostTypeId` (`PostTypeId`),
KEY `AcceptedAnswerId` (`AcceptedAnswerId`),
KEY `OwnerUserId` (`OwnerUserId`),
KEY `LastEditorUserId` (`LastEditorUserId`),
KEY `ParentId` (`ParentId`),
CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`PostTypeId`) REFERENCES `posttypes` (`PostTypeId`)
) ENGINE=InnoDB;
Prueba esto:
SELECT jos_categories.title AS name,
joined .catid,
joined .title,
joined .introtext
FROM jos_categories
INNER JOIN (SELECT *
FROM (SELECT `title`,
catid,
`created`,
introtext
FROM `jos_content`
WHERE `sectionid` = 6
ORDER BY `id` DESC) AS yes
GROUP BY `yes`.`catid` DESC
ORDER BY `yes`.`created` DESC) AS joined
ON( joined.catid = jos_categories.id )
Puedes verlo desde aquí también.
http://sqlfiddle.com/#!9/ef42b/9
Primera solucion
SELECT d1.ID,Name,City FROM Demo_User d1
INNER JOIN
(SELECT MAX(ID) AS ID FROM Demo_User GROUP By NAME) AS P ON (d1.ID=P.ID);
Segunda solucion
SELECT * FROM (SELECT * FROM Demo_User ORDER BY ID DESC) AS T GROUP BY NAME ;
Qué tal esto:
SELECT DISTINCT ON (name) *
FROM messages
ORDER BY name, id DESC;
Tuve un problema similar (en hard postgresql) y en una tabla de registros de 1M. Esta solución toma 1.7s contra 44s producidos por el que tiene LEFT JOIN. En mi caso, tuve que filtrar el corrispondant de su campo de nombre contra valores NULL, lo que resultó en mejores resultados en 0.2 segundos
Si desea la última fila para cada Name
, puede asignar un número de fila a cada grupo de filas por Name
y orden por Id
en orden descendente.
CONSULTA
SELECT t1.Id,
t1.Name,
t1.Other_Columns
FROM
(
SELECT Id,
Name,
Other_Columns,
(
CASE Name WHEN @curA
THEN @curRow := @curRow + 1
ELSE @curRow := 1 AND @curA := Name END
) + 1 AS rn
FROM messages t,
(SELECT @curRow := 0, @curA := '''') r
ORDER BY Name,Id DESC
)t1
WHERE t1.rn = 1
ORDER BY t1.Id;
SQL Fiddle
Si el rendimiento es realmente su preocupación, puede introducir una nueva columna en la tabla llamada IsLastInGroup
de tipo BIT.
Establézcalo en verdadero en las últimas columnas y manténgalo con cada fila insertar / actualizar / eliminar. Las escrituras serán más lentas, pero te beneficiarás con las lecturas. Depende de su caso de uso y lo recomiendo solo si está centrado en la lectura.
Entonces tu consulta se verá como:
SELECT * FROM Messages WHERE IsLastInGroup = 1
Solución por sub consulta
select * from messages where id in
(select max(id) from messages group by Name)
Solución por unión condición fiddle link
select m1.* from messages m1
left outer join messages m2
on ( m1.id<m2.id and m1.name=m2.name )
where m2.id is null
La razón de esta publicación es dar solo el enlace de violín. El mismo SQL ya se proporciona en otras respuestas.
Todavía no he probado con grandes bases de datos, pero creo que esto podría ser más rápido que unir tablas:
SELECT *, Max(Id) FROM messages GROUP BY Name
Un acercamiento con velocidad considerable es el siguiente.
SELECT *
FROM messages a
WHERE Id = (SELECT MAX(Id) FROM messages WHERE a.Name = Name)
Resultado
Id Name Other_Columns
3 A A_data_3
5 B B_data_2
6 C C_data_1
Usa tu subquery para devolver la agrupación correcta, porque estás a mitad de camino.
Prueba esto:
select
a.*
from
messages a
inner join
(select name, max(id) as maxid from messages group by name) as b on
a.id = b.maxid
Si no es id
, desea el máximo de:
select
a.*
from
messages a
inner join
(select name, max(other_col) as other_col
from messages group by name) as b on
a.name = b.name
and a.other_col = b.other_col
De esta manera, evita subconsultas y / o ordenaciones correlacionadas en sus subconsultas, que tienden a ser muy lentas / ineficientes.
UPD: 2017-03-31, la versión 5.7.5 de MySQL hizo que el conmutador ONLY_FULL_GROUP_BY se habilitara por defecto (por lo tanto, las consultas GROUP BY no deterministas se deshabilitaron). Además, actualizaron la implementación de GROUP BY y la solución podría dejar de funcionar como se esperaba, incluso con el interruptor deshabilitado. Uno tiene que comprobar.
La solución anterior de Bill Karwin funciona bien cuando el recuento de elementos dentro de los grupos es bastante pequeño, pero el rendimiento de la consulta se vuelve malo cuando los grupos son bastante grandes, ya que la solución requiere aproximadamente n*n/2 + n/2
de solo comparaciones IS NULL
.
Hice mis pruebas en una tabla InnoDB de 18684446
filas con 1182
grupos. La tabla contiene los resultados de las pruebas para las pruebas funcionales y tiene la clave principal (test_id, request_id)
. Por lo tanto, test_id
es un grupo y estaba buscando el último request_id
para cada test_id
.
La solución de Bill ya se ha estado ejecutando durante varias horas en mi dell e4310 y no sé cuándo finalizará, aunque funcione con un índice de cobertura (por lo tanto, using index
en EXPLAIN).
Tengo un par de otras soluciones basadas en las mismas ideas:
- si el índice subyacente es el índice BTREE (que suele ser el caso), el par más grande
(group_id, item_value)
es el último valor dentro de cadagroup_id
, que es el primero para cadagroup_id
si recorremos el índice en orden descendente; - si leemos los valores que están cubiertos por un índice, los valores se leen en el orden del índice;
- cada índice contiene implícitamente columnas de clave primaria adjuntas a eso (es decir, la clave principal se encuentra en el índice de cobertura). En las soluciones a continuación, opero directamente en la clave principal, en su caso, solo tendrá que agregar columnas de clave principal en el resultado.
- en muchos casos es mucho más barato recopilar los ID de fila requeridos en el orden requerido en una subconsulta y unir el resultado de la subconsulta en el ID. Como para cada fila en el resultado de la subconsulta, MySQL necesitará una única recuperación basada en la clave primaria, la subconsulta se colocará primero en la unión y las filas se mostrarán en el orden de los identificadores de la subconsulta (si omitimos explícitamente ORDER BY para la unión)
3 formas en que MySQL usa índices es un gran artículo para entender algunos detalles.
Solución 1
Este es increíblemente rápido, toma aproximadamente 0,8 segundos en mis 18M + filas:
SELECT test_id, MAX(request_id), request_id
FROM testresults
GROUP BY test_id DESC;
Si desea cambiar el orden a ASC, póngalo en una subconsulta, devuelva solo los identificadores y utilícelo como subconsulta para unirse al resto de las columnas:
SELECT test_id, request_id
FROM (
SELECT test_id, MAX(request_id), request_id
FROM testresults
GROUP BY test_id DESC) as ids
ORDER BY test_id;
Esta toma alrededor de 1,2 segundos en mis datos.
Solucion 2
Aquí hay otra solución que toma alrededor de 19 segundos para mi mesa:
SELECT test_id, request_id
FROM testresults, (SELECT @group:=NULL) as init
WHERE IF(IFNULL(@group, -1)=@group:=test_id, 0, 1)
ORDER BY test_id DESC, request_id DESC
También devuelve las pruebas en orden descendente. Es mucho más lento ya que realiza una exploración de índice completa, pero está aquí para darle una idea de cómo generar N filas máximas para cada grupo.
La desventaja de la consulta es que su caché de consulta no puede almacenar en caché su resultado.
SELECT
column1,
column2
FROM
table_name
WHERE id IN
(SELECT
MAX(id)
FROM
table_name
GROUP BY column1)
ORDER BY column1 ;
select * from messages group by name desc