2012-06-12 14 views
31

Diciamo che ho una tabella chiamata messages con le colonne:Come ottenere l'ultimo record in ogni gruppo utilizzando GROUP BY?

id | from_id | to_id | subject | message | timestamp 

voglio ottenere l'ultimo messaggio da ogni utente solo, come si farebbe vedere nella tua casella di posta FaceBook prima di drill-down nella filettatura reale.

Questa query sembra di farmi vicino al risultato ho bisogno:

SELECT * FROM messages GROUP BY from_id 

Tuttavia la query mi sta dando il messaggio più vecchio da ciascun utente e non il più recente.

Non riesco a capire questo.

+0

C'è anche una soluzione migliore a questo problema [qui] (http://stackoverflow.com/questions/1313120/retrieving-the-last- record-in-each-group) –

risposta

74

si dovrebbe capire ultimi timestamp valori in ciascun gruppo (subquery), e poi unirsi a questa subquery alla tabella -

SELECT t1.* FROM messages t1 
    JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages GROUP BY from_id) t2 
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp; 
+4

+1 Un problema comune, ma grazie mille per non aver utilizzato la funzione MySQL di consentire le colonne nella selezione che non fanno parte del gruppo! – GarethD

+0

Grazie mille! Sono stato in grado di partecipare a un tavolo aggiuntivo senza problemi. Un buon approccio – user1019144

+0

Questo è semplicemente perfetto. – enchance

-4

È necessario ordinarli.

SELECT * FROM messages GROUP BY from_id ORDER BY timestamp DESC LIMIT 1

+0

seleziona top (1) * .... – BumbleB2na

+0

@ BumbleB2na 'LIMIT 1' intendi? – Li0liQ

+0

ora avrai l'ultimo messaggio di TUTTI I MESSAGGI, hai bisogno di una condizione dove – jcho360

1

Questo è un problema standard.

Si noti che MySQL consente di omettere le colonne dalla clausola GROUP BY, che SQL standard non consente, ma non si ottengono risultati deterministici in generale quando si utilizza la funzione MySQL.

SELECT * 
    FROM Messages AS M 
    JOIN (SELECT To_ID, From_ID, MAX(TimeStamp) AS Most_Recent 
      FROM Messages 
     WHERE To_ID = 12345678 
     GROUP BY From_ID 
     ) AS R 
    ON R.To_ID = M.To_ID AND R.From_ID = M.From_ID AND R.Most_Recent = M.TimeStamp 
WHERE M.To_ID = 12345678 

ho aggiunto un filtro sulla To_ID per corrispondere a ciò che è molto probabile che avere. La query funzionerà senza di essa, ma restituirà molti più dati in generale. Non è necessario che la condizione sia dichiarata sia nella query nidificata che nella query esterna (l'ottimizzatore dovrebbe sospendere automaticamente la condizione), ma non può fare nulla per ripetere la condizione come mostrato.

+0

L'ultimo standard SQL consente di omettere le colonne nel 'GROUP BY' e includerli nella clausola' SELECT' o 'HAVING', a condizione che funzionino in modo funzionale sulla combinazione' GROUP BY' - e quindi saranno restituiti solo risultati deterministici. (Naturalmente MySQL non esegue questo controllo.) –

+0

@ypercube Non sono sicuro se questo è il posto giusto per questo, ma hai qualche link valido per questo. Non riesco a capire come selezionare colonne che non sono nel gruppo potrebbe diventare deterministico dipendendo da elementi nel gruppo, l'unico modo che vedo per renderlo non deterministico è attraverso l'uso di order by. Tuttavia vedere esempi può aiutare a chiarire le cose. Grazie – GarethD

+0

'GROUP BY pk' sarebbe un semplice esempio. La mia risposta [qui] (http://stackoverflow.com/questions/7594865/why-does-mysql-add-a-feature-that-conflicts-with-sql-standards/7596265#7596265) ha un collegamento a (una copia di) lo standard. –

2

Proprio integrando quello che ha detto Devart, il codice qui sotto non è ordinare in base alla domanda:

SELECT t1.* FROM messages t1 
    JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages GROUP BY from_id) t2 
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp; 

Il "GROUP BY" clausola deve essere nella query principale dato che abbiamo bisogno prima riordinare le "SOURCE" per ottenere il necessario "raggruppamento", così:

SELECT t1.* FROM messages t1 
    JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages ORDER BY timestamp DESC) t2 
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp GROUP BY t2.timestamp; 

saluti,

12

Prova questo

SELECT * FROM messages where id in (SELECT max(id) FROM messages GROUP BY from_id) order by id desc 
+3

Sebbene questo codice possa rispondere alla domanda, sarebbe meglio includere qualche _context_, spiegando _how_ funziona e _quando_ per usarlo. Le risposte al solo codice non sono utili a lungo termine. –

+0

"SELEZIONA max (id) FROM messaggi GROUP BY from_id" questa query interna, raggruppa prima i record/i messaggi per utente (da_id) e quindi trascina l'ID record massimo. Quindi stiamo interrogando di nuovo sulla tabella dei messaggi per ottenere solo i record/messaggi più recenti dal set di risultati della query interna. –

+0

La soluzione più semplice IMHO – Nowdeen

2

questa query ritorno ultimo disco per ogni Form_id:

SELECT m1.* 
    FROM messages m1 LEFT JOIN messages m2 
    ON (m1.Form_id = m2.Form_id AND m1.id < m2.id) 
    WHERE m2.id IS NULL; 
+0

Onestamente questa risposta è sottovalutata. Questa è stata l'unica soluzione che ha funzionato bene per me poiché sto raggruppando in un campo diverso oltre al mio campo di incremento automatico e devo selezionare l'ultima per data. –

+0

Questa risposta mi ha aiutato a farlo funzionare con Hibernate HQL. Nessuna delle altre risposte ha funzionato, poiché Hibernate supporta le subquery solo dopo WHERE e SELECT. Poiché questa risposta non utilizza alcuna subquery, ha funzionato bene. – Alex