Лучший способ построить этот запрос?

Возможный дубликат:
Поиск последней записи в каждая группа

У меня есть две таблицы, похожие на эту (упрощенную для квеста):

действия-

id - user_id - action - time

пользователи -

id - name

Я хочу вывести последнее действие для каждого пользователя. Я понятия не имею, как это сделать.

Я не очень хорошо разбираюсь в SQL, но из того, что я просмотрел, это должно выглядеть примерно так. хотя не уверен.

SELECT `users`.`name`, *
FROM users, actions
JOIN < not sure what to put here >
ORDER BY `actions`.`time` DESC
< only one per user_id >

Любая помощь будет оценена по достоинству.


person Andrew    schedule 17.04.2010    source источник
comment
Что ж, ответ уже принят, но если хотите, у вас есть хорошая лекция: stackoverflow.com/questions/1907534/   -  person Savageman    schedule 18.04.2010


Ответы (5)


вам нужно сделать групповой максимум - см. примеры здесь http://jan.kneschke.de/projects/mysql/groupwise-max/

вот пример, который я сделал для кого-то другого, который похож на ваши требования:

http://pastie.org/925108

select
 u.user_id,
 u.username,
 latest.comment_id
from
 users u
left outer join
(
  select
   max(comment_id) as comment_id,
   user_id
  from
   user_comment
  group by
   user_id
 ) latest on u.user_id = latest.user_id;
person Jon Black    schedule 17.04.2010

выберите u.name, a.action, a.time
от пользователя u, action a
где u.id = a.user_id
и a.time in (выберите max(time) из действие, где user_id = u.user_id группа по user_id )



примечание не проверено, но это должно быть шаблоном

person Randy    schedule 17.04.2010

Это самая большая проблема n на группу, которая часто возникает при переполнении стека. Подпишитесь на тег, чтобы увидеть десятки других сообщений по этой проблеме.

Вот как это сделать в MySQL, учитывая вашу схему без подзапросов и без GROUP BY:

SELECT u.*, a1.*
FROM users u JOIN actions a1 ON (u.id = a1.user_id)
LEFT OUTER JOIN actions a2 ON (u.id = a2.user_id AND a1.time < a2.time)
WHERE a2.id IS NULL;

Другими словами, покажите пользователю его действие таким образом, что если мы будем искать другое действие с тем же пользователем и позже, мы не найдем ничего.

person Bill Karwin    schedule 17.04.2010

Мне кажется, что следующие будут работы

WITH GetMaxTimePerUser (user_id, time) (
    SELECT user_id, MAX(time)
    FROM actions
    GROUP BY user_id
)
SELECT u.name, a.action, amax.time
FROM actions AS a
    INNER JOIN users AS u ON u.id=a.user_id
    INNER JOIN GetMaxTimePerUser AS u_maxtime ON u_maxtime.user_id=u.id
WHERE a.time=u_maxtime.time

Использование временного именованного набора результатов (общее табличное выражение или CTE) без подзапросов и OUTER JOIN лучше всего подходит для оптимизации запросов. (CTE - это что-то вроде VIEW, но существующее только виртуальное или встроенное)

person Oleg    schedule 18.04.2010

person    schedule
comment
По какой-то конкретной причине вы используете подзапрос? Выглядит немного сложно для работы, не так ли? - person Decent Dabbler; 18.04.2010
comment
В основном незнание SQL, я использую подзапросы все время, когда, вероятно, не должен :). Если есть лучший способ, вы должны опубликовать его как отдельный ответ - person Michael Mrozek; 18.04.2010
comment
Ну, честно говоря, я тоже не гуру SQL... Я подумал, что у вас может быть какая-то гениальная причина, почему вы делаете это именно так. ;-) - person Decent Dabbler; 18.04.2010
comment
Ой. В таком случае я так и сделал. Фантастически гениальная причина, для объяснения которой потребуются страницы и страницы сложных формул. - person Michael Mrozek; 18.04.2010