2013-06-25 11 views
6

(Non riesco a parlare inglese molto bene, ma cercherò di fare il mio meglio)MySQL che seleziona valori distinti ordine per data/ora

Ho due tabelle.

table1

 
id carid user 
--------------------- 
1 | A001 | user1 
2 | A002 | user1 
3 | A003 | user2 
4 | A002 | user3 

table2

 
id carid  datetime   lat  lon 
---------------------------------------------------- 
1 | A001 | 2013-25-06 10:00:00 | -23.0000 | -46.0000 
2 | A002 | 2013-25-06 10:01:00 | -24.3500 | -45.3200 
3 | A002 | 2013-25-06 10:02:00 | -24.3800 | -45.3300 
4 | A001 | 2013-25-06 10:05:00 | -23.0500 | -46.1000 
5 | A003 | 2013-25-06 10:07:00 | -24.3500 | -45.3200 
6 | A001 | 2013-25-06 10:10:00 | -23.0700 | -46.1200 

ho bisogno di selezionare ogni registro distinto "CARID" da "user1" ordinato da datetime

Risultato ho bisogno:

 
    carid   datetime   lat  lon 
-------------------------------------------------- 
    A001 | 2013-25-06 10:10:00 | -23.0700 |-46.1200 
    A002 | 2013-25-06 10:02:00 | -24.3800 |-45.3300 

Il modo in cui sto realizzando è la selezione di tutti i "carid" da parte dell'utente che desidero e selezionando ogni riga singolarmente tramite .net.

`SELECT carid FROM table1 where user = “user1”;` 
 
carid 
----- 
A001 
A002 

poi selezionando la riga che voglio:

SELECT * FROM table2 WHERE car_id='A001' ORDER BY datetime DESC limit 1 
SELECT * FROM table2 WHERE car_id='A002' ORDER BY datetime DESC limit 1 

Ma a seconda del numero di registri "di CARID" da quell'utente devo fare un sacco di querys. Non so se è possibile farlo con un solo SELEZIONA migliorare il modo in cui sto facendo, ma questo è quello che ho provato:

SELECT car_id, datetime, lat, lon from table1 
INNER JOIN table2 on carid = car_id 
WHERE user = 'user1' 
GROUP BY carid 
ORDER BY datetime DESC; 

Risultato:

 
carid datetime   lat   lon 
------------------------------------------------------ 
A002 | 2013-25-06 10:01:00 | -24.3500 | -45.3200 
A001 | 2013-25-06 10:02:00 | -23.0000 | -46.0000 

E ho provato anche questo:

SELECT car_id, MAX(datetime) as datetime, lat, lon from table1 
INNER JOIN table2 on carid = car_id 
WHERE user = 'user1' 
GROUP BY carid 
ORDER BY datetime DESC; 

Risultato:

 
carid  datetime   lat   lon 
------------------------------------------------------ 
A001 | 2013-25-06 10:10:00 | -23.0000 | -46.0000 
A002 | 2013-25-06 10:02:00 | -24.3500 | -45.3200 

Ma il risultato che ho ottenuto è sbagliato. Non so cosa fare senza selezionare tutte le righe, che è un modo più lento del modo in cui lo realizzo.

Qualche idea?

+2

+1 per una domanda ben scritta con i dati della tabella e come si è tentato di risolvere il problema. – Taryn

risposta

6

Puoi partecipare a table2 due volte, una volta per ottenere la max(datetime) per ogni carId e la seconda per ottenere il lat e lon associato alla carId e datetime:

select t1.carid, t2.datetime, t2.lat, t2.lon 
from table1 t1 
inner join 
(
    -- get the lat/lon associated with each carid and max datetime 
    select t2.carid, t2.datetime, t2.lat, t2.lon 
    from table2 t2 
    inner join 
    (
    -- get the max datetime for each carid 
    select carid, max(datetime) datetime 
    from table2 
    group by carid 
) d 
    on t2.carid = d.carid 
    and t2.datetime = d.datetime 
) t2 
    on t1.carid = t2.carid 
where user = 'user1'; 

Vedi SQL Fiddle with Demo.

vostra query con il max() tornava sbagliate lat e lon valori, perché si esegue il raggruppamento solo dalla carid modo MySQL può arbitrariamente selezionare i valori per le colonne nell'elenco di selezione che non sono in una funzione di aggregazione o di un GROUP BY. Questo comportamento è dovuto a MySQL's Extensions to GROUP BY.

dalla documentazione MySQL:

MySQL estende l'uso di GROUP BY in modo che l'elenco di selezione può fare riferimento alle colonne nonaggregated non citati nella clausola GROUP BY. ... È possibile utilizzare questa funzione per ottenere prestazioni migliori evitando l'ordinamento e il raggruppamento non necessari delle colonne. Tuttavia, ciò è utile principalmente quando tutti i valori in ogni colonna non aggregata non denominata in GROUP BY sono uguali per ciascun gruppo. Il server è libero di scegliere qualsiasi valore da ciascun gruppo, quindi a meno che non siano gli stessi, i valori scelti sono indeterminati. Inoltre, la selezione dei valori di ciascun gruppo non può essere influenzata dall'aggiunta di una clausola ORDER BY. L'ordinamento del set di risultati si verifica dopo aver scelto i valori e ORDER BY non influisce sui valori scelti dal server.

Per essere sicuri di restituire i valori corretti, si vorrà utilizzare una sottoquery simile alla precedente.

+0

Grazie per il tempo che hai impiegato per rispondere. In questo modo funziona davvero come volevo, ma richiede più tempo del modo in cui spiegavo che stavo facendo, sfortunatamente. Contrassegnato come risposta. – Sagevalle

+0

@Sagevalle Hai qualche indice sui tuoi tavoli? – Taryn

+0

Sì, in ** Table1 **'carid' e'user' e in ** Table2 **'carid'. – Sagevalle

0

Penso che la seguente query dovrebbe funzionare per lo scenario. Non ho provato lo stesso dato che non ho i dati.

SELECT 
    t1.carid, t2.datetime, t2.lat, t2.lon 
FROM 
    table1 t1 JOIN table2 t2 
    ON t1.carid = t2.carid AND t1.user='user1' 
GROUP BY 
    carid 
HAVING 
    t2.datetime=MAX(datetime); 

Fammi sapere se funziona.

+0

Non ha funzionato. – Sagevalle