2012-07-27 31 views
9

Mi mesa titles se parece a estoMySQL ordenar por fecha GROUP BY

id |group|date    |title 
---+-----+--------------------+-------- 
1 |1 |2012-07-26 18:59:30 | Title 1 
2 |1 |2012-07-26 19:01:20 | Title 2 
3 |2 |2012-07-26 19:18:15 | Title 3 
4 |2 |2012-07-26 20:09:28 | Title 4 
5 |2 |2012-07-26 23:59:52 | Title 5 

que necesita el último resultado de cada grupo por fecha en orden descendente. Algo como esto

id |group|date    |title 
---+-----+--------------------+-------- 
5 |2 |2012-07-26 23:59:52 | Title 5 
2 |1 |2012-07-26 19:01:20 | Title 2 

me trató

SELECT * 
FROM `titles` 
GROUP BY `group` 
ORDER BY MAX(`date`) DESC 

pero estoy geting primeros resultados de los grupos. Me gusta esto

id |group|date    |title 
---+-----+--------------------+-------- 
3 |2 |2012-07-26 18:59:30 | Title 3 
1 |1 |2012-07-26 19:18:15 | Title 1 

¿Qué estoy haciendo mal? ¿Esta consulta va a ser más complicada si utilizo LEFT JOIN?

+0

Si solo necesita las dos columnas (por ejemplo, ID y su última marca de tiempo), esto podría funcionar: http://stackoverflow.com/a/4448536/722036. Es ** más rápido ** que usar subconsultas en una tabla enorme con millones de filas. –

Respuesta

8

This page fue muy útil para mí; me enseñó cómo usar autouniones para obtener las filas max/min/something-n por grupo.

En su situación, se puede aplicar al efecto que desea de este modo:

SELECT * FROM 
(SELECT group, MAX(date) AS date FROM titles GROUP BY group) 
AS x JOIN titles USING (group, date); 
0

Bueno, si las fechas son únicos en un grupo que esto funciona (si no, verá varias filas que coincide con la fecha máxima en un grupo). (También, mal de nombres de columnas, 'grupo', 'fecha' podría darle errores de sintaxis y como 'grupo' especialmente)

select t1.* from titles t1, (select group, max(date) date from titles group by group) t2 
where t2.date = t1.date 
and t1.group = t2.group 
order by date desc 
0

Otro enfoque es hacer uso de variables de usuario de MySQL para identificar una "ruptura de control "en los valores group.

Si se puede vivir con que se devuelve una columna adicional, algo como esto funcionará:

SELECT IF(s.group = @prev_group,0,1) AS latest_in_group 
    , s.id 
    , @prev_group := s.group AS `group` 
    , s.date 
    , s.title 
    FROM (SELECT t.id,t.group,t.date,t.title 
      FROM titles t 
     ORDER BY t.group DESC, t.date DESC, t.id DESC 
     ) s 
    JOIN (SELECT @prev_group := NULL) p 
HAVING latest_in_group = 1 
ORDER BY s.group DESC 

Lo que esto hace es ordenar todas las filas por group y por date en orden descendente. (Especificamos DESC en todas las columnas de ORDER BY, en caso de que exista un índice en (group,date,id) en el que MySQL pueda hacer un "análisis reverso". La inclusión de la columna id nos da un comportamiento determinístico (repetible), en el caso de hay más de una fila con el último valor date). Esa es la vista en línea alias como s.

El "truco" que utilizamos es comparar el valor group con el valor group de la fila anterior. Cada vez que tenemos un valor diferente, sabemos que estamos comenzando un grupo "nuevo", y que esta fila es la "última" fila (tenemos la función SI devuelve un 1). De lo contrario (cuando los valores del grupo coinciden), no es la última fila (y tenemos la función SI devuelve un 0).

Luego filtramos todas las filas que no tienen ese latest_in_group establecido como 1.

Es posible eliminar esa columna adicional envolviendo esa consulta (como una vista en línea) en otra consulta:

SELECT r.id 
    , r.group 
    , r.date 
    , r.title 
    FROM (SELECT IF(s.group = @prev_group,0,1) AS latest_in_group 
       , s.id 
       , @prev_group := s.group AS `group` 
       , s.date 
       , s.title 
      FROM (SELECT t.id,t.group,t.date,t.title 
        FROM titles t 
        ORDER BY t.group DESC, t.date DESC, t.id DESC 
       ) s 
      JOIN (SELECT @prev_group := NULL) p 
     HAVING latest_in_group = 1 
     ) r 
ORDER BY r.group DESC 
0

Si su campo id es un campo de incremento automático, y es seguro decir que la el valor máximo del campo id es también el valor más alto para el date de cualquier grupo, entonces esta es una solución simple:

SELECT b.* 
FROM  (SELECT MAX(id) AS maxid FROM titles GROUP BY group) a 
JOIN  titles b ON a.maxid = b.id 
ORDER BY b.date DESC 
0

utilizar la consulta mysql abajo para recibir las últimas registro actualizado/insertado desde la mesa .

SELECT * FROM 
(
    select * from `titles` order by `date` desc 
) as tmp_table 
group by `group` 
order by `date` desc 
1

Encontré este tema en Google, parecía que tenía el mismo problema. Aquí está mi propia solución si, como yo, no te gusta subconsultas:

-- Create a temporary table like the output 
CREATE TEMPORARY TABLE titles_tmp LIKE titles; 

-- Add a unique key on where you want to GROUP BY 
ALTER TABLE titles_tmp ADD UNIQUE KEY `group` (`group`); 

-- Read the result into the tmp_table. Duplicates won't be inserted. 
INSERT IGNORE INTO titles_tmp 
    SELECT * 
    FROM `titles` 
    ORDER BY `date` DESC; 

-- Read the temporary table as output 
SELECT * 
    FROM titles_tmp 
    ORDER BY `group`; 

Tiene una forma mejor rendimiento. Aquí es cómo aumentar la velocidad si el date_column tiene el mismo orden que el auto_increment_one (que entonces no necesita una instrucción ORDER BY):

-- Create a temporary table like the output 
CREATE TEMPORARY TABLE titles_tmp LIKE titles; 

-- Add a unique key on where you want to GROUP BY 
ALTER TABLE titles_tmp ADD UNIQUE KEY `group` (`group`); 

-- Read the result into the tmp_table, in the natural order. Duplicates will update the temporary table with the freshest information. 
INSERT INTO titles_tmp 
    SELECT * 
    FROM `titles` 

    ON DUPLICATE KEY 
    UPDATE `id` = VALUES(`id`), 
      `date` = VALUES(`date`), 
      `title` = VALUES(`title`); 

-- Read the temporary table as output 
SELECT * 
    FROM titles_tmp 
    ORDER BY `group`; 

Resultado:

+----+-------+---------------------+---------+ 
| id | group | date    | title | 
+----+-------+---------------------+---------+ 
| 2 |  1 | 2012-07-26 19:01:20 | Title 2 | 
| 5 |  2 | 2012-07-26 23:59:52 | Title 5 | 
+----+-------+---------------------+---------+ 

en tablas grandes Este método hace un punto significativo en términos de rendimiento.

0

utilizar la siguiente consulta para obtener el registro más reciente de cada grupo

SELECT 
T1.* FROM 
(SELECT 
    MAX(ID) AS maxID 
FROM 
    T2 
GROUP BY Type) AS aux 
    INNER JOIN 
T2 AS T2 ON T1.ID = aux.maxID ; 

donde id es el campo de incremento automático y tipo es el tipo de registros, que querían agrupar.

0

MySQL usa una extensión muda de GROUP BY que no es fiable si se desea conseguir tales resultados, por lo tanto, se puede usar

select id, group, date, title from titles as t where id = 
(select id from titles where group = a.group order by date desc limit 1); 

En esta consulta, cada vez que la mesa es escaneado completo para cada grupo por lo que puede encontrar la fecha más reciente. No pude encontrar un mejor suplente para esto. Espero que esto ayude a alguien.