2013-06-25 17 views
6

(Nie mówię po angielsku bardzo dobrze, ale postaram się jak mogę)Wybieranie MySQL wartości według datetime

Mam dwie tabele.

tabela1

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

Tabela 2

 
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 

muszę wybrać każdy odrębny rejestr "carid" z "user1" zamówionej przez datetime

Wynik muszę:

 
    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 

Sposób, w jaki robię, polega na zaznaczeniu wszystkich "karid" od żądanego użytkownika i wybraniu każdego wiersza pojedynczo przez .net.

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

Następnie wybierając wiersz chcę:

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 

Ale w zależności od liczby rejestrów „carid” od tego użytkownika muszę zrobić wiele querys. Nie wiem, czy to możliwe, aby to zrobić z pojedynczym SELECT poprawy sposobu robię, ale to, co próbowałem:

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; 

Wynik:

 
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 

I ja też próbowałem to:

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; 

Wynik:

 
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 

Ale wynik jest błędny. Nie wiem, co zrobić bez wybrania wszystkich wierszy, co jest wolniejsze niż sposób, w jaki naprawdę to robię.

Jakieś myśli?

+2

+1 za dobrze napisane pytanie z danymi tabeli i sposób, w jaki próbujesz rozwiązać swój problem. – Taryn

Odpowiedz

6

Możesz dołączyć na table2 dwa razy, raz, aby uzyskać max(datetime) dla każdego carId a drugi, aby uzyskać lat i lon związane z carId i 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'; 

Zobacz SQL Fiddle with Demo.

Zapytanie z max() wracał niewłaściwych lat i lon wartości, ponieważ są grupowania tylko przez carid tak MySQL może dowolnie wybrać wartości dla kolumn na liście select, które nie są w zagregowanej funkcji lub GROUP BY. To zachowanie jest spowodowane MySQL's Extensions to GROUP BY.

Od docs MySQL:

MySQL rozszerza stosowanie GROUP BY tak, że lista wyboru może odnosić się do nonaggregated kolumn nie wymienionych w klauzuli GROUP BY. ... Możesz użyć tej funkcji, aby uzyskać lepszą wydajność, unikając niepotrzebnego sortowania i grupowania kolumn. Jest to jednak przydatne przede wszystkim wtedy, gdy wszystkie wartości w każdej niezagregowanej kolumnie nienazwanej w GROUP BY są takie same dla każdej grupy. Serwer może dowolnie wybrać dowolną wartość z każdej grupy, więc jeśli nie są one takie same, wybrane wartości są nieokreślone. Ponadto nie można wpłynąć na wybór wartości z każdej grupy poprzez dodanie klauzuli ORDER BY. Sortowanie zestawu wyników następuje po wybraniu wartości, a ORDER BY nie wpływa na wartości wybierane przez serwer.

Aby mieć pewność, że zwracasz prawidłowe wartości, będziesz chciał użyć podkwerendy podobnej do powyższej.

+0

Dziękujemy za czas poświęcony na odpowiedź. Tak naprawdę działa tak, jak chciałem, ale zajmuje mi to więcej czasu, niż niestety, jak wyjaśnię. Oznaczone jako odpowiedź. – Sagevalle

+0

@Sagevalle Czy masz jakieś indeksy na swoich stołach? – Taryn

+0

Tak, w ** Tabeli 1 ** "carid" i "user" oraz w ** Tabeli 2 ** "karid". – Sagevalle

0

Myślę, że następujące zapytanie powinno działać dla twojego scenariusza. Nie próbowałem tego samego, ponieważ nie mam danych.

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); 

Daj mi znać, jeśli to działa.

+0

To nie zadziałało. – Sagevalle