2011-01-25 22 views
19

Ho cercato il sito per assistenza ma ancora in difficoltà. Ecco la mia tabella:Selezionare il record più recente nella tabella (campo datetime)

 
messages 
======== 
id 
thread_id 
user_id 
subject 
body 
date_sent 

In sostanza, voglio recuperare l'ultimo record per ogni thread_id. Ho provato il seguente:

SELECT id, thread_id, user_id, subject, body, date_sent 
FROM messages 
WHERE user_id=1 AND date_sent=(select max(date_sent)) 
GROUP BY thread_id 
ORDER BY date_sent DESC 

MA mi sta dando i record più vecchi, non i più nuovi!

Chi può consigliare?

EDIT: Tabella discarica:

 
-- 
-- Table structure for table `messages` 
-- 

CREATE TABLE IF NOT EXISTS `messages` (
    `id` int(10) unsigned NOT NULL auto_increment, 
    `thread_id` int(10) unsigned NOT NULL, 
    `user_id` int(10) unsigned NOT NULL, 
    `body` text NOT NULL, 
    `date_sent` datetime NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=34 ; 

-- 
-- Dumping data for table `messages` 
-- 

INSERT INTO `messages` (`id`, `thread_id`, `user_id`, `body`, `date_sent`) VALUES 
(1, 1, 1, 'Test Message', '2011-01-20 00:13:51'), 
(2, 1, 6, 'Test Message', '2011-01-20 01:03:50'), 
(3, 1, 6, 'Test Message', '2011-01-20 01:22:52'), 
(4, 1, 6, 'Test Message', '2011-01-20 11:59:01'), 
(5, 1, 1, 'Test Message', '2011-01-20 11:59:22'), 
(6, 1, 6, 'Test Message', '2011-01-20 12:10:37'), 
(7, 1, 1, 'Test Message', '2011-01-20 12:10:51'), 
(8, 2, 6, 'Test Message', '2011-01-20 12:45:29'), 
(9, 1, 6, 'Test Message', '2011-01-20 13:08:42'), 
(10, 1, 1, 'Test Message', '2011-01-20 13:09:49'), 
(11, 2, 1, 'Test Message', '2011-01-20 13:10:17'), 
(12, 3, 1, 'Test Message', '2011-01-20 13:11:09'), 
(13, 1, 1, 'Test Message', '2011-01-21 02:31:43'), 
(14, 2, 1, 'Test Message', '2011-01-21 02:31:52'), 
(15, 4, 1, 'Test Message', '2011-01-21 02:31:57'), 
(16, 3, 1, 'Test Message', '2011-01-21 02:32:10'), 
(17, 4, 6, 'Test Message', '2011-01-20 22:36:57'), 
(20, 1, 6, 'Test Message', '2011-01-20 23:02:36'), 
(21, 4, 1, 'Test Message', '2011-01-20 23:17:22'); 

EDIT: Scuse - forse ho preso le cose un po 'confuso qui - in fondo quello che voglio è quello di recuperare tutti i messaggi per un determinato user_id, quindi trovare l'ultimo messaggio (per thread_id) da quei messaggi recuperati.

+0

E 'il tipo di ordinamento che è il problema o è la selezione della registrazione più vecchia per ogni utente piuttosto che il più nuovo? – ChrisF

+0

Seleziona il record più vecchio anziché il più recente. L'ordine BY funziona correttamente. – GSTAR

+0

Sareste in grado di fornire un dump della tabella in questione con alcuni valori precompilati in modo che possa testare la mia query su di esso. Penso di avere un modo molto più semplice di usare una subquery scalare e di non utilizzare tutti i join incrociati di gruppo ecc. – andrew

risposta

33
SELECT id, thread_id, user_id, subject, body, date_sent 
    FROM messages WHERE date_sent IN (
    SELECT MAX(date_sent) 
     FROM messages WHERE user_id =6 GROUP BY thread_id 
) 
    ORDER BY thread_id ASC , date_sent DESC; 

farmi sapere se funziona ora

+0

Grazie capo, è perfetto. Continuerà a testare e accetterà la tua risposta se tutto va bene. – GSTAR

+0

Grazie, ha lavorato anche per me! – Alyas

+0

Ci sono molte cose che non vanno in questa query, ma i bug saranno insidiosi e non li troverai finché non ci saranno molti dati. Proverò a scrivere la mia risposta. – PaulC

4

È un processo a due fermate. Prima trova le date più recenti per ogni thread_id. Quindi selezionare i record che hanno queste date e corrispondenza thread_id s

SELECT t.id, t.thread_id, t.user_id, t.body, t.date_sent 
FROM messages AS t 
CROSS JOIN (
    SELECT thread_id, MAX(date_sent) AS date_sent FROM messages WHERE user_id = 1 GROUP BY thread_id 
) AS sq 
USING (thread_id, date_sent) 

Nota che se due (o più) messages hanno stesso date_sent e lo stesso thread_id saranno entrambi selezionati (perché non si può dire che uno è più recente)

+0

È tutto vero. Questa operazione è spesso chiamata "groupwise max". Per ulteriori esempi, leggi questo: http://jan.kneschke.de/projects/mysql/groupwise-max/ ... o Google per "groupwise max". – TehShrike

+0

Grazie per questo. Puoi fornire un esempio che usi una sintassi simile a quello che ho usato, cioè senza CROSS JOIN e USING? So che il tuo metodo è probabilmente più efficace ma preferisco usare la semplice sytnax a cui sono abituato :) – GSTAR

+0

Fornire un dump della tabella con alcuni valori precompilati e penso di poter scrivere una query molto più semplice con una sottoquery scalare. E non si baserà su cross join o groups – andrew

1

Da quello che posso vedere, il tuo problema si trova con la sotto-query. La sottoquery estrarrà in realtà il massimo campo date_sent dal record corrente, in altre parole, poiché la query esterna attraversa la tabella un record alla volta i due campi date_sent nella subquery "date_sent=(select max(date_sent)" saranno sempre gli stessi . Dopo aver visualizzato il primo record per un determinato thread_id, non mostra nessun altro record per quel thread_id poiché si sta raggruppando per thread_id. Questo è il motivo per cui mostrerà sempre il primo record inserito per ogni thread_id. A proposito, sta mostrando il primo record inserito per ogni thread_id e non il primo record date_sent. Il risultato dipende dalla posizione del record nella tabella e non dal valore di date_sent. Non so se mi sono spiegata correttamente, ma in ogni caso, per risolvere il problema prova:

SELECT id, thread_id, user_id, subject, body, date_sent 
FROM messages 
WHERE user_id=1 AND date_sent IN (select max(date_sent) from messages GROUP BY thread_id) 
GROUP BY thread_id 
ORDER BY date_sent DESC; 

In primo luogo, il sub-query deve avere una clausola FROM e una clausola GROUP BY per tirare sulle date massimi per ID_Thread dall'intera tabella e non solo il record corrente. Inoltre, lo = deve essere sostituito con uno IN poiché la sottoquery potrebbe generare più record. Se la tabella contiene due record dello stesso ID thread nella stessa data, verrà visualizzato solo il primo. Ciò è causato dalla seconda clausola GROUP BY nella query esterna. Per visualizzare tutti i record per quel ID_Thread in quel giorno, provare:

SELECT id, thread_id, user_id, subject, body, date_sent 
FROM messages 
WHERE user_id =1 AND date_sent IN (SELECT MAX(date_sent) FROM messages GROUP BY thread_id) 
ORDER BY thread_id ASC , date_sent DESC; 

Rimuovendo il secondo GROUP BY clausola e l'aggiunta di una clausola ORDER BY, è possibile visualizzare tutti i messaggi per quella data massima per ogni ID_Thread ed ancora visualizzare i fili nell'ordine corretto. Spero possa aiutare.

+0

Ciao amico, grazie per questo. Ho provato entrambe le tue query, ma ogni volta non restituisce il numero corretto di record per un dato id_utente. Non ci sono date doppie nel mio set di dati. – GSTAR

+0

Fondamentalmente sembra che ignori totalmente alcuni thread_id. – GSTAR

+0

OK Potrei avere delle cose un po 'confuse qui - in pratica quello che voglio è recuperare tutti i messaggi per un dato user_id, POI trovare l'ultimo messaggio (per thread_id) da quei messaggi recuperati. – GSTAR

1

Questa è una domanda veramente vecchio, ma comunque ...

La tua clausola where non è abbastanza specifica e usare date_sent per selezionare il record giusto è semplicemente sbagliato. Prova questo:

SELECT id, thread_id, user_id, subject, body, date_sent 
FROM messages 
WHERE id=(
    select m2.id from messages m2 
    where messages.thread_id=m2.thread_id 
    order by date_sent desc limit 1) 
ORDER BY date_sent DESC 

Se si vuole assumere che id sempre aumenta nel corso del tempo, questo sarebbe probabilmente un rendimento migliore:

SELECT id, thread_id, user_id, subject, body, date_sent 
FROM messages 
WHERE id in (
    select max(m2.id) from messages m2 group by m2.thread_id) 
ORDER BY date_sent DESC 
Problemi correlati