MySQL – Controla qué fila es devuelta por un grupo

Tengo una tabla de base de datos como esta:

id version_id field1 field2 1 1 texta text1 1 2 textb text2 2 1 textc text3 2 2 textd text4 2 3 texte text5 

Si no lo resolvió, contiene varias versiones de una fila y luego algunos datos de texto.

Quiero consultarlo y devolver la versión con el número más alto para cada identificación. (por lo tanto, la segunda y la última fila solo en el anterior).

He intentado usar group by ordenando por version_id DESC – pero parece ordenar después de agrupado, así que esto no funciona.

¿Alguien tiene alguna idea? ¡No puedo creer que no se pueda hacer!

ACTUALIZAR:

Vamos con esto, que funciona, pero usa una subconsulta:

 SELECT * FROM (SELECT * FROM table ORDER BY version_id DESC) t1 GROUP BY t1.id 

Se llama seleccionar el máximo de una columna para el grupo. Aquí hay varios enfoques diferentes para mysql.

Así es como lo haría:

 SELECT * FROM (SELECT id, max(version_id) as version_id FROM table GROUP BY id) t1 INNER JOIN table t2 on t2.id=t1.id and t1.version_id=t2.version_id 

Esto será relativamente eficiente, aunque mysql creará una tabla temporal en la memoria para la subconsulta. Supongo que ya tiene un índice en (id, version_id) para esta tabla.

Es una deficiencia en SQL que más o menos tenga que usar una subconsulta para este tipo de problema ( las semiunidades son otro ejemplo).

Las subconsultas no están bien optimizadas en mysql, pero las subconsultas no correlacionadas no son tan malas, siempre y cuando no sean tan enormes que se escribirán en el disco en lugar de en la memoria. Dado que en esta consulta solo tiene dos entradas, la subconsulta podría ser de millones de filas mucho antes de que eso ocurriera, pero la subconsulta de selección * en su primera consulta podría sufrir este problema mucho antes.

Creo que esto lo haría, pero no estoy seguro de si es el mejor o el más rápido.

 SELECT * FROM table WHERE (id, version_id) IN (SELECT id, MAX(version_id) FROM table GROUP BY id) 
 SELECT id, version_id, field1, field2 FROM ( SELECT @prev = id AS st, (@prev := id), m.* FROM ( (SELECT @prev := NULL) p, ( SELECT * FROM mytable ORDER BY id DESC, version_id DESC ) m ) m2 WHERE NOT IFNULL(st, FALSE); 

Sin subconsultas, un pase en UNIQUE INDEX ON MYTABLE (id, version_id) si tiene uno (que creo que debería)

Normalmente hago esto con una subconsulta:

seleccione id, version_id, campo1, campo2 de datatable como dt donde id = (seleccione id de datatable donde id = dt.id orde por version_id desc limit 1)

Esto es un pseudo código, pero algo como esto debería funcionar bien

 select * from table inner join ( select id , max(version_id) maxVersion from table ) dvtbl ON id = dvtbl.id && versionid = dvtbl.maxVersion 

Esta consulta hará el trabajo sin un grupo por:

 SELECT * FROM table AS t LEFT JOIN table AS t2 ON t.id=t2.id AND t.version_id < t2.version_id WHERE t2.id IS NULL 

No necesita tablas temporales.

Siempre se pueden utilizar funciones analíticas que le den más control

select tmp.* from ( select id,version_id,field1,field2, rank() over(partition by id order by version_id desc ) as rnk from table) tmp where tmp.rnk=1

Si tiene problemas con la función rank () dependiendo del tipo de datos, entonces uno puede elegir entre row_number () o dense_rank () también.

Creo que esto es lo que quieres.

 select id, max(v_id), field1, field2 from table group by id 

Los resultados que obtengo de eso son

1, 2, textb, text2

2, 3, texto, texto5

Editar: Recreé la tabla e inserté los mismos datos con el ID y una version_id como clave primaria compuesta. Esto dio la respuesta que proporcioné anteriormente. También estaba en MySQL.

no probado, pero algo como esto podría funcionar:

SELECCIONAR * FROM tabla GROUP BY id ORDER BY MAX (version_id) DESC