2011-01-25 7 views
19

Przeszukałem witrynę, aby uzyskać pomoc, ale nadal boryka się z problemami. Oto mój stół:Wybierz najnowszy rekord w tabeli (pole datetime)

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

Zasadniczo chcę pobrać najnowszy rekord dla każdego id_wątku. Próbowałem następujące:

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 

ALE daje mi najstarsze rekordy, a nie najnowsze!

Ktoś może doradzić?

EDIT: Tabela wysypisko:

 
-- 
-- 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: Przepraszam - może mam co nieco mylić tutaj - w zasadzie to, co chcę jest, aby pobrać wszystkie wiadomości dla danego user_id, a następnie znaleźć najnowsze wiadomości (za thread_id) z tych pobranych wiadomości.

+0

Czy to porządek w tym tkwi problem, czy jest to wybierając najstarszy rekord każdy użytkownik, a nie najnowszy? – ChrisF

+0

Wybiera najstarszy rekord zamiast najnowszego. ORDER BY działa poprawnie. – GSTAR

+0

Czy możesz podać zrzut tabeli z niektórymi wstępnie wypełnionymi wartościami, aby przetestować na niej moje zapytanie. Myślę, że mam o wiele prostszy sposób, używając skalarnego podzapytania i nie używając wszystkich krzyżówek grupowych itp. – andrew

Odpowiedz

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; 

Daj mi znać, jeśli działa teraz

+0

Dzięki szefie, to jest idealne. Będzie kontynuować test i zaakceptuje twoją odpowiedź, jeśli wszystko będzie w porządku. – GSTAR

+0

Dzięki, pracowałem też dla mnie! – Alyas

+0

W tym zapytaniu jest wiele błędów, ale błędy będą podstępne i nie znajdziesz ich, dopóki nie pojawi się dużo danych. Spróbuję napisać własną odpowiedź. – PaulC

4

Jest to proces dwupołożeniowy. Najpierw znajdź najnowsze daty dla każdego thread_id. Następnie wybierz rekordy, które mają te daty i dopasowanie 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) 

pamiętać, że jeśli dwie (lub więcej) messages mieć taką samą date_sent i sam thread_id będą zarówno być wybrane (bo nie można powiedzieć, który z nich jest nowszy)

+0

To wszystko prawda. Ta operacja jest często nazywana "groupwise max". Aby uzyskać jeszcze więcej przykładów, przeczytaj: http://jan.kneschke.de/projects/mysql/groupwise-max/ ... lub Google dla "groupwise max". – TehShrike

+0

Dzięki za to. Czy możesz podać przykład, który używa podobnej składni do tego, z czego korzystałem, tj. Bez CROSS JOIN i USING? Wiem, że twoja metoda jest prawdopodobnie bardziej efektywna, ale wolę używać prostego sytnaxa, do którego jestem przyzwyczajony :) – GSTAR

+0

Zapewnij zrzut tabeli z pewnymi wstępnie wypełnionymi wartościami i myślę, że mogę napisać znacznie prostsze zapytanie za pomocą skalarnego podzapytania. I nie będzie można polegać na łączeniach krzyżowych lub grupowych – andrew

1

Z tego co widzę, Twój problem polega na pod-zapytaniu. Zapytanie podrzędne będzie faktycznie wyodrębniało maksymalne pole date_sent z bieżącego rekordu, innymi słowy, ponieważ zapytanie zewnętrzne przechodzi przez tabelę po jednym rekordzie w czasie, gdy dwa pola date_sent w pod-zapytaniu "date_sent=(select max(date_sent)" będą zawsze takie same. . Po wyświetleniu pierwszego rekordu dla określonego id_wątku, nie wyświetla żadnych innych rekordów dla tego id_wątku, ponieważ grupujesz według wątku. Dlatego zawsze będzie wyświetlany pierwszy rekord wprowadzony dla każdego id_wątku. BTW pokazuje pierwszy rekord wpisany dla każdego id_wątku, a nie najwcześniejszy rekord date_sent. Twój wynik zależy od lokalizacji rekordu w tabeli, a nie od wartości date_sent. Nie wiem, czy to wyjaśniłem poprawnie, ale tak, aby rozwiązać swój problem spróbować:

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; 

Po pierwsze, sub-query musi mieć FROM klauzuli i GROUP BY klauzuli podciągnąć maksymalny termin na thread_id z całego tabela, a nie tylko aktualny rekord. Ponadto = musi zostać zastąpiony przez IN, ponieważ pod-zapytanie może skutkować wieloma rekordami. Jeśli tabela zawiera dwa zapisy o tym samym identyfikatorze wątku w tym samym dniu, zostanie wyświetlony tylko pierwszy. Jest to spowodowane przez drugą klauzulę GROUP BY w zapytaniu zewnętrznym. Aby wyświetlić wszystkie rekordy dla tej thread_id w tym dniu, spróbuj:

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; 

Usuwając drugą GROUP BY klauzuli i dodanie klauzuli ORDER BY można wyświetlić wszystkie wiadomości na ten maksymalnym terminem dla każdego thread_id i nadal wyświetlać wątki w poprawnej kolejności. Nadzieja, która pomaga.

+0

Cześć kolego, dziękuję za to. Próbowałem obu zapytań, ale za każdym razem nie zwracano poprawnej liczby rekordów dla danego user_id. W zbiorze danych nie ma zduplikowanych dat. – GSTAR

+0

Zasadniczo wygląda na to, że całkowicie ignoruję wątki thread_id. – GSTAR

+0

OK Możliwe, że mam tu trochę zamieszania - w zasadzie to, czego chcę, to pobranie wszystkich wiadomości dla danego user_id, TO znajduję najnowszą wiadomość (na thread_id) z tych pobranych wiadomości. – GSTAR

1

Jest to bardzo stare pytanie, ale w każdym razie ...

Twoja klauzula where nie jest wystarczająco dokładna, a użycie date_sent do wybrania właściwego rekordu jest po prostu niepoprawne. Spróbuj tego:

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 

Jeśli chcesz się założyć, że id zawsze wzrasta w miarę upływu czasu, to pewnie lepiej:

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 
Powiązane problemy