2009-02-11 5 views
49

Tengo una tabla de base de la siguiente manera:MySQL - Control de la fila que se devuelve por un grupo de

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 trabaja a cabo, que contiene una serie de versiones de una fila, y luego algunos datos de texto.

Deseo 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 el grupo al ordenar por version_id DESC - pero parece ordenar después de su agrupación, por lo que esto no funciona.

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

ACTUALIZACIÓN:

llegado con esto, que funciona, pero utiliza una subconsulta:

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

Relacionado: http://stackoverflow.com/questions/13700456/mysql-group-by-implementation-details-which-row-mysql-chooses-in-a-group-by-qu – ripper234

Respuesta

44

Se llama seleccionando la máxima grupo racional de una columna. Here are several different approaches for mysql.

Así es como yo 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 

Ésta 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 tiene que usar una subconsulta para este tipo de problema (semi-joins son otro ejemplo).

Las subconsultas no están bien optimizadas en mysql pero las subconsultas no correlacionadas no son tan malas siempre que no sean tan enormes que se escribirán en el disco en lugar de 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.

+3

El artículo vinculado es muy ¡bonito! – onnodb

+0

Ta para el enlace y ejemplo. Terminamos yendo con la opción de subconsulta. – benlumley

+0

+1 para el artículo vinculado. Gracias. – dotancohen

3

Creo que esto lo haría, 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) 
+0

Podría estar equivocado, pero me parece que la subconsulta se ejecutará para cada fila y luego se probará (aunque puede haber algo de almacenamiento en caché) ... ¿Es eso cierto? – Buksy

+0

Eso es extremadamente improbable, lo que probablemente haría es crear una tabla temporal con los resultados de la subconsulta y compararlos. Sin embargo, no puedo hablar de todos los sistemas de bases de datos. –

0

Ésta es 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 
0

que suelo hacer esto con una subconsulta:

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

-1

Creo que esto es lo que quiere.

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

Los resultados que recibo de que son

1, 2, textb, texto2

2, 3, texte, text5

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

+0

que no funciona, de ahí la pregunta: el grupo devolverá la fila que resulte ser la primera en el grupo, junto con la cantidad máxima para la versión en el grupo. – benlumley

+0

no, esto funciona ... Recreé la tabla que tenía y luego ejecuté la consulta y funcionó bien. –

+0

@Berek: 'fraid not. "[El servidor es libre de elegir cualquier valor de cada grupo, por lo tanto, a menos que sean iguales, los valores elegidos son indeterminados. \ [.. \] En algunos casos, puede usar MIN() y MAX() para obtener un valor específico de ** columna ** incluso si no es exclusivo.] (http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html) " –

2
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); 

No subconsultas, una pasada en UNIQUE INDEX ON MYTABLE (id, version_id) si tiene uno (que yo creo que debería)

-2

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

SELECT * FROM tabla GROUP por ID ORDER BY DESC MAX (version_id)

0

Esta consulta puede hacer 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.

Cuestiones relacionadas