2012-10-05 14 views
6

Ho visto un tipo simile di domande qui, ma nessuno di loro ha aiutato la mia situazione.Gruppo MySQL per ID e ultimo datetime

Ho una tabella diciamo di prova (usando MySQL MyISAM)

test ha il seguente schema:

TID INT PRIMARY KEY AUTO_INCREMENT 
    TData varchar (data that i want to select) 
    TUserID INT (this will be joined with users table, same users can have many records here) 
    TViewedAt DATETIME (records each time user visits page, datetime format) 

Ora ogni volta che una pagina di prova è visitato da utente attualmente connesso, si aggiunge record a questa tabella registrando l'ID utente che ha visitato, alcuni dati e la data e l'ora in cui l'utente visitato con TID viene incrementato automaticamente ogni volta.

Quindi ho una pagina di gestione del back-end in cui posso vedere quale pagina di test visitata dall'utente, quante volte, dati e quando. Fondamentalmente è una tabella con un elenco di 20-25 ultime righe. My Query dovrebbe selezionare solo un record per dati. I dati possono essere uguali per l'utente ma in tempi diversi ma voglio solo selezionare un dato per ogni utente che è il più recente. Quindi, se l'utente ha visitato la pagina di prova 10 volte, 10 record vanno al database ma visualizza solo l'ultimo record sulla tabella. Se un altro utente visita la pagina 15 volte, visualizza 1 record per questo secondo utente, che è l'ultimo di nuovo, quindi in totale ora abbiamo 2 righe visualizzate sul tavolo. Ho ottenuto tutto per funzionare ma GROUP BY per qualche motivo e MAX (data) non mi dà l'ultimo datetime per ogni data.

ecco la mia domanda:

SELECT * 
    FROM Test 
    WHERE TUserID = 123 
    GROUP BY TData 
    ORDER BY TViewedAt 

restituisce 2 righe da cui nessuna di queste righe sono le ultime.

grazie sacco

risposta

11

Penso che con il sotto è possibile ottenere ciò di cui si ha bisogno, Queste operazioni sono così definite "Group-wise Maximum".

Opzione 1

Questo è il più facile da capire, una subquery tornerà massima TID per tutti gli utenti dal momento che il max viene utilizzato in insieme a Group By e di noi un altro query per ottenere tutti i dati per quegli ID.

Select TID, TData, TUserID, TViewedAt 
From Test 
Where TID In(
    Select Max(TID) 
    From Test 
    Group By TUserID 
) 

Opzione 2

Un po 'più complessa da capire, ma molto probabilmente più efficiente, Questo funziona sulla base del fatto che, quando t1.TViewedAt è al suo valore massimo, non c'è t2.TViewedAt con un valore maggiore e i valori delle righe t2 saranno NULL.

SELECT t1.TID, t1.TData, t1.TUserID, t1.TViewedAt 
FROM Test t1 
LEFT JOIN Test t2 ON t1.TUserID = t2.TUserID AND t1.TViewedAt < t2.TViewedAt 
WHERE t2.TUserID IS NULL; 

Risultato

TID TData TUserID TViewedAt 
4 test3 123  2012-10-05 00:00:00.000 
5 test2 213  2012-10-03 00:00:00.000 
+0

sì è funzionante, grazie mille, molto semplice e facile – Giorgi

+0

benvenuto, felice di aiutare –

+1

c'è un modo per fare questo che è più efficiente, cioè non richiede subquery? Sto scoprendo che sta uccidendo il mio server – Jason

1

È necessario GROUP BY TUserID per l'aggregato max.

SELECT 
    TID, 
    TData, 
    main.TUserID 
    main.TViewedAt 
FROM 
    yourTable main 
    JOIN ( 
    SELECT TUserID, MAX(TViewedAt) AS TViewedAT FROM yourTable GROUP BY TUserID 
) tmax ON main.TUserID = tmax.TUserID AND main.TViewedAt = tmax.TViewedAt 

Questo è un metodo portatile che si unisce a una sottoquery. La sottoquery richiama l'ultimo TUserID,TViewedAt per utente e questo viene unito di nuovo contro la tabella principale per far corrispondere lo TData.

Se si desidera un solo utente alla volta, si può fare:

SELECT 
    TData, 
    TViewedAt 
FROM yourTable 
WHERE TUserID = 'someid' 
GROUP BY TUserId 
HAVING TViewedAt = MAX(TViewedAt) 

È possibile che questo funziona solo in MySQL il modo in cui ho scritto, però. Altri RDBMS si lamenteranno del fatto che TData appare nell'elenco SELECT ma non è nello GROUP BY.

+0

la seconda ho provato e restituito 0 righe. TViewedAt è il formato DATETIME MAX lo capisce? – Giorgi

+1

@Giorgi MAX() comprende le colonne datetime. Usa il primo ma aggiungi una clausola WHERE per limitare l'utente che desideri. Il primo è il migliore e più portatile dei due. –

0
SELECT t1.TData, t1.TUserID, t1.TViewedAt 
FROM Test t1 
JOIN 
(SELECT TUserID, MAX(TViewedAt) 
FROM Test 
GROUP BY TUserID) t2 
ON t1.TUserID = t2.TUserID AND t1.TViewedAt=t2.TViewedAt 
+0

che non ha funzionato :( – Giorgi

+0

Scusa, ho dimenticato che il TData potrebbe essere diverso. Quindi vedi gli aggiornamenti ... – alex

1

seguente query, può aiutarti-

select * from pages where date(create_date)=(select date(create_date) from pages order by create_date limit 1) 
+1

Puoi spiegare come questo risponde alla domanda? – Braiam