2012-07-27 14 views
9

Il mio tavolo titles assomiglia a questoMySQL sono ordinati per data, con 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 

Ho bisogno ultimo risultato di ogni gruppo ordinato per data in ordine decrescente. Qualcosa di simile

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

ho provato

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

ma sto geting primi risultati dai gruppi. Mi piace questo

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

Cosa sto facendo male? Questa query sarà più complicata se utilizzo LEFT JOIN?

+0

Se sono necessarie solo le due colonne (ad esempio ID e il suo timestamp più recente), questo potrebbe funzionare: http://stackoverflow.com/a/4448536/722036. È ** più veloce ** rispetto all'utilizzo di sottoquery su una tabella enorme con milioni di righe. –

risposta

8

This page è stato molto utile per me; mi ha insegnato come usare i self-join per ottenere le righe max/min/something-n per gruppo.

Nella tua situazione, può essere applicato per l'effetto che si desidera in questo modo:

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

Beh, se sono unici in un gruppo date questo potrebbe funzionare (se non, si vedrà più righe che corrisponde alla data massima in un gruppo). (Inoltre, cattivo denominazione di colonne, 'gruppo', 'data' potrebbe dare errori di sintassi e quali appositamente 'gruppo')

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

Un altro approccio è quello di fare uso di MySQL variabili utente per identificare una "pausa di controllo "nei valori group.

Se si può vivere con una colonna in più di essere tornato, qualcosa di simile a questo lavoro:

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 

Che cosa questo sta facendo è ordinare tutte le righe da group e date in ordine decrescente. (Specifichiamo DESC su tutte le colonne in ORDER BY, nel caso in cui ci sia un indice su (group,date,id) su cui MySQL può eseguire una "scansione inversa". L'inclusione della colonna id ci dà un comportamento deterministico (ripetibile), nel caso in cui ci sono più di una riga con l'ultimo valore date.) Questa è la vista in linea con alias come s.

Il "trucco" che usiamo è di confrontare il valore group con il valore group della riga precedente. Ogni volta che abbiamo un valore diverso, sappiamo che stiamo avviando un gruppo "nuovo" e che questa riga è la riga "ultima" (abbiamo la funzione IF restituisce 1). Altrimenti (quando i valori di gruppo corrispondono), non è l'ultima riga (e abbiamo la funzione IF restituisce uno 0).

Quindi, filtriamo tutte le righe che non hanno lo latest_in_group impostato come 1.

E 'possibile rimuovere quella colonna in più avvolgendo quella query (come vista in linea) in un altro query:

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

Se il campo id è un campo incremento automatico, ed è sicuro di dire che la più alto valore del campo id è anche il valore più alto per la date di qualsiasi gruppo, allora questa è una soluzione semplice:

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

Utilizzare la query mysql qui sotto per ottenere ultima aggiornata di registrazione/inserita da tavolo .

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

Ho trovato questo argomento tramite Google, sembrava che avessi lo stesso problema. Ecco la mia soluzione se, come me, non ti piace sottointerrogazioni:

-- 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`; 

Ha un modo migliore performance. Ecco come aumentare la velocità se il colonna_data ha lo stesso ordine del auto_increment_one (allora non hai bisogno di un'istruzione 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`; 

Risultato:

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

Su grandi tavoli questo metodo fa un punto significativo in termini di prestazioni.

0

utilizzare la seguente query per ottenere il record più recente da ogni gruppo

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 ; 

dove ID è il vostro campo di incremento automatico e tipo è il tipo di record, è voluto dal gruppo.

0

MySQL utilizza un'estensione muto di GROUP BY, che non è affidabile se si desidera ottenere tali risultati, pertanto, è possibile utilizzare

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

In questa query, ogni volta che il tavolo viene sottoposto a scansione completa per ogni gruppo in modo da può trovare la data più recente. Non ho trovato nessun altro migliore per questo. Spero che questo aiuti qualcuno.