2011-01-25 2 views
19

Я искал сайт для помощи, но все еще борется. Вот мой стол:Выберите последнюю запись в таблице (поле даты и времени)

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

В основном я хочу получить самую последнюю запись для каждого потока_ид. Я пробовал следующее:

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 

НО, но это дает мне самые старые записи, а не новейшие!

Любой, кто может посоветовать?

EDIT: Таблица свалка:

 
-- 
-- 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: Извинения - я, возможно, есть вещи немного запутанные здесь - в основном то, что я хочу, чтобы получить все сообщения для данного user_id, а затем найти самое последнее сообщение (на thread_id) из полученных сообщений.

+0

ли порядок сортировки, что проблема или это выбрать самую старую запись для каждый пользователь, а не самый новый? – ChrisF

+0

Он выбирает самую старую запись, а не самую новую. ORDER BY работает нормально. – GSTAR

+0

Вы могли бы предоставить дамп рассматриваемой таблицы с некоторыми предварительно заполненными значениями, чтобы я мог проверить свой запрос на нем. Я думаю, что у меня гораздо проще использовать скалярный подзапрос и не использовать все групповые перекрестные соединения и т. Д. – andrew

ответ

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; 

Позвольте мне знать, если он работает сейчас

+0

Спасибо, босс, это прекрасно. Будет продолжать тестировать и будет принимать ваш ответ, если все ОК. – GSTAR

+0

Спасибо, Работал и для меня! – Alyas

+0

В этом запросе есть много чего, но ошибки будут коварными, и вы их не найдете, пока не будет много данных. Я попытаюсь написать свой собственный ответ. – PaulC

4

Это процесс с двумя остановками. Сначала найдите самые новые даты для каждого thread_id. Затем выберите записи, которые имеют эти даты и соответствие thread_id сек

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) 

Обратите внимание, что если два (или более) messages имеет такое же date_sent и то же thread_id они оба будут выбраны (потому что вы не можете сказать, какой из них новее)

+0

Все это правда. Эту операцию часто называют «groupwise max». Для получения еще нескольких примеров прочтите следующее: http://jan.kneschke.de/projects/mysql/groupwise-max/ ... или Google для «группового максимума». – TehShrike

+0

Спасибо за это. Можете ли вы привести пример, который использует аналогичный синтаксис для того, что я использовал, т. Е. Без CROSS JOIN и USING? Я знаю, что ваш метод, вероятно, более эффективен, но я предпочитаю использовать простой sytnax, к которому я привык :) – GSTAR

+0

Предоставьте дамп вашей таблицы с некоторыми заранее заполненными значениями, и я думаю, что я могу написать вам гораздо более простой запрос, используя скалярный подзапрос. И он не будет полагаться на кросс-соединения или группы by – andrew

1

Из того, что я вижу, ваша проблема заключается в подзапросе. Подзапрос фактически будет извлекать максимальное поле date_sent из текущей записи, другими словами, поскольку внешний запрос пересекает запись по одной записи за раз, когда два поля date_sent в подзапросе «date_sent=(select max(date_sent)» всегда будут одинаковыми , После того, как он отображает первую запись для определенного потока_ид, он не отображает никаких других записей для этого потока_ид, поскольку вы группируете thread_id. Поэтому всегда будет отображаться первая запись, введенная для каждого thread_id. BTW, он показывает первую запись, введенную для каждого потока thread_id, а не самую раннюю запись date_sent. Ваш результат зависит от местоположения записи в вашей таблице, а не от значения date_sent. Не уверен, что если бы я объяснил это правильно, но в любом случае, чтобы исправить вашу проблему попробовать:

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; 

Во-первых, подзапрос должен иметь пункт FROM и пункт GROUP BY подтянуть максимальные сроки за thread_id от ЦЕЛОМ таблицу, а не только текущую запись. Кроме того, = должен быть заменен на IN, поскольку подзапрос может привести к нескольким записям. Если таблица содержит две записи одного и того же идентификатора потока в одну и ту же дату, будет отображаться только первая. Это вызвано вторым предложением GROUP BY во внешнем запросе. Чтобы отобразить все записи для этого thread_id в тот день, попробуйте:

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; 

Удалив второй GROUP BY пункт и добавление ORDER BY пункта, вы можете показать все сообщения для этого максимального срока для каждого thread_id и до сих пор отображения темы в правильном порядке. Надеюсь, это поможет.

+0

Привет, друг, спасибо. Я попробовал оба ваших запроса, но каждый раз он не возвращает правильное количество записей для данного user_id. В моем наборе данных нет повторяющихся дат. – GSTAR

+0

В принципе, кажется, что полностью игнорирует некоторые thread_id. – GSTAR

+0

OK У меня, возможно, есть вещи, которые немного запутались здесь - в основном, я хочу, чтобы получить все сообщения для данного user_id, ТОГДА найти последнее сообщение (за поток_ид) из этих полученных сообщений. – GSTAR

1

Это очень старый вопрос, но в любом случае ...

Предложение where не является достаточно конкретным, и использование date_sent для выбора правильной записи просто неверно. Попробуйте это:

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 

Если вы хотите, чтобы предположить, что идентификатор всегда возрастает с течением времени, это, вероятно, работать лучше:

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 
Смежные вопросы