Il problema dell'"ultimo per gruppo" è estremamente comune in SQL. Ci sono innumerevoli esempi di soluzioni a questo stesso problema solo su questo sito.
Se i tuoi timestamp sono unici per attività del membro:
SELECT
m.id,
m.name,
a.code activity_code,
a.timestamp activity_timestamp,
a.description activity_description
FROM
members m
INNER JOIN activities a ON a.member_id = m.id
WHERE
a.timestamp = (SELECT MAX(timestamp) FROM activities WHERE member_id = m.id)
in alternativa, se il tuo ID attività aumenta in modo monotono con il tempo:
...
WHERE
a.id = (SELECT MAX(id) FROM activities WHERE member_id = m.id)
Non è necessario raggruppare. Ma la query trarrà vantaggio da un indice su activities
su (member_id, timestamp)
o (member_id, id)
, rispettivamente.
MODIFICA
Per mostrare tutti i membri che non hanno registrato un'attività, usa un join sinistro come questo.
SELECT
m.id,
m.name,
a.code activity_code,
a.timestamp activity_timestamp,
a.description activity_description
FROM
members m
LEFT JOIN activities a ON
a.member_id = m.id
AND a.timestamp = (SELECT MAX(timestamp) FROM activities WHERE member_id = m.id)
Nota che non c'è WHERE
clausola. Semanticamente, WHERE viene applicato dopo le giunzioni sono fatte. Quindi una clausola WHERE rimuoverebbe le righe aggiunte da LEFT JOIN, dando effettivamente lo stesso risultato dell'INNER JOIN originale.
Ma se applichi il predicato aggiuntivo direttamente nella condizione di unione, LEFT JOIN funzionerà come previsto.