2012-06-12 12 views
31

Powiedzmy mam tabeli o nazwie messages z kolumnami:Jak uzyskać najnowszy rekord w każdej grupie przy użyciu GROUP BY?

id | from_id | to_id | subject | message | timestamp 

Chcę otrzymywać najnowsze wiadomości od każdego użytkownika tylko, jak można zobaczyć w swojej skrzynce odbiorczej FaceBook przed drążyć do rzeczywistych wątku.

To zapytanie wydaje się mi blisko do wyniku muszę:

SELECT * FROM messages GROUP BY from_id 

Jednak kwerendy daje mi najstarszą wiadomość od każdego użytkownika, a nie najnowszy.

Nie mogę wymyślić tego.

+0

Jest nawet lepszym rozwiązaniem tego problemu [tutaj] (http://stackoverflow.com/questions/1313120/retrieving-the-last- record-in-each-group) –

Odpowiedz

74

Należy dowiedzieć się ostatnie timestamp wartości w każdej grupie (podzapytanie), a następnie dołączyć do tej podzapytanie do stołu -

SELECT t1.* FROM messages t1 
    JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages GROUP BY from_id) t2 
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp; 
+4

+1 Powszechny problem, ale dziękuję bardzo za to, że nie używasz funkcji MySQL pozwalających na kolumny w selekcji, których nie ma w grupie! – GarethD

+0

Dziękuję SOOO dużo! Udało mi się dołączyć do dodatkowego stołu bez problemu. Takie dobre podejście. – user1019144

+0

To jest po prostu idealne. – enchance

-4

Musisz je zamówić.

SELECT * FROM messages GROUP BY from_id ORDER BY timestamp DESC LIMIT 1

+0

wybierz górę (1) * .... – BumbleB2na

+0

@ BumbleB2na 'LIMIT 1' masz na myśli? – Li0liQ

+0

teraz dostaniesz ostatnią wiadomość WSZYSTKICH KOMUNIKATÓW, potrzebujesz warunku gdzie – jcho360

1

Jest to standardowy problem.

Zauważ, że MySQL pozwala pominąć kolumny z klauzuli GROUP BY, których nie ma Standardowy SQL, ale generalnie nie uzyskujesz deterministycznych wyników podczas korzystania z funkcji MySQL.

SELECT * 
    FROM Messages AS M 
    JOIN (SELECT To_ID, From_ID, MAX(TimeStamp) AS Most_Recent 
      FROM Messages 
     WHERE To_ID = 12345678 
     GROUP BY From_ID 
     ) AS R 
    ON R.To_ID = M.To_ID AND R.From_ID = M.From_ID AND R.Most_Recent = M.TimeStamp 
WHERE M.To_ID = 12345678 

Dodałem filtr na To_ID dopasować co jesteś prawdopodobne, aby mieć. Zapytanie będzie działało bez niego, ale zwróci znacznie więcej danych w ogóle. Warunek nie musi być podawany zarówno w zapytaniu zagnieżdżonym, jak i w zapytaniu zewnętrznym (optymalizator powinien automatycznie wypychać warunek), ale nie może zaszkodzić powtórzeniu warunku, jak pokazano.

+0

Najnowszy Standard SQL pozwala pominąć kolumny w 'GROUP BY' i dołącz je do klauzuli' SELECT' lub 'HAVING', pod warunkiem, że są funkcjonalnie zależne od kombinacji GROUP BY, a zatem zwracane są tylko wyniki deterministyczne. (MySQL nie ma takiego czeku oczywiście.) –

+0

@ypercube Nie jestem pewien, czy to miejsce dla tego, ale czy masz jakieś dobre linki do tego. Nie potrafię zrozumieć, w jaki sposób wybieranie kolumn, które nie należą do grupy, może stać się deterministyczne poprzez uzależnienie od elementów w grupie, jedyny sposób, jaki widzę, aby uczynić go nie deterministycznym, to wykorzystanie porządku przez. Jednak zobaczenie przykładów może pomóc wyjaśnić sprawę. Dzięki – GarethD

+0

"GROUP BY pk" będzie prostym przykładem. Moja odpowiedź [tutaj] (http://stackoverflow.com/questions/7594865/why-does-mysql-add-a-feature-at-conflicts-w-sql-standards/7596265#7596265) ma link do (kopia z) standardu. –

2

Wystarczy uzupełniając co Devart powiedział, poniższy kod nie jest zamawianie zgodnie z pytaniem:

SELECT t1.* FROM messages t1 
    JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages GROUP BY from_id) t2 
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp; 

„grupa BY” klauzuli musi być w głównym zapytaniu ponieważ musimy najpierw zmienić kolejność na „źródło” aby uzyskać potrzebne "grupowanie" So:

SELECT t1.* FROM messages t1 
    JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages ORDER BY timestamp DESC) t2 
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp GROUP BY t2.timestamp; 

Pozdrowienia,

12

Spróbuj

SELECT * FROM messages where id in (SELECT max(id) FROM messages GROUP BY from_id) order by id desc 
+3

Podczas gdy ten kod może odpowiedzieć na pytanie, lepiej byłoby dodać jakiś _context_, wyjaśniający _how_ to działa i _when_, aby go użyć. Odpowiedzi tylko na kod nie są przydatne na dłuższą metę. –

+0

"WYBIERZ max (id) z wiadomości GROUP BY od from_id" to zapytanie wewnętrzne, najpierw grupuje rekordy/wiadomości według użytkownika (from_id), a następnie wyciągając max identyfikator rekordu. Następnie ponownie wysyłamy zapytania do tabeli komunikatów, aby uzyskać tylko najnowsze rekordy/wiadomości z wewnętrznego zestawu wyników zapytania. –

+0

Najprostsze rozwiązanie IMHO – Nowdeen

2

ten powrót zapytanie ostatni rekord dla każdego Form_id:

SELECT m1.* 
    FROM messages m1 LEFT JOIN messages m2 
    ON (m1.Form_id = m2.Form_id AND m1.id < m2.id) 
    WHERE m2.id IS NULL; 
+0

Szczerze mówiąc, ta odpowiedź jest niedoceniana. To było jedyne rozwiązanie, które sprawdziło się dobrze, ponieważ jestem zgrupowany w innym polu niż moje pole automatycznego przyrostu i muszę wybrać najnowsze według daty. –

+0

Ta odpowiedź pomogła mi w pracy z Hibernate HQL. Żadna z pozostałych odpowiedzi nie zadziałała, ponieważ Hibernate obsługuje podzapytania tylko po WHERE i SELECT. Ponieważ ta odpowiedź nie używa żadnych podkwerend, w ogóle działała. – Alex