Выберите строку с последней датой для каждого пользователя
у меня есть таблица ("lms_attendance") времени регистрации и выхода пользователей, которая выглядит так:
id user time io (enum)
1 9 1370931202 out
2 9 1370931664 out
3 6 1370932128 out
4 12 1370932128 out
5 12 1370933037 in
Я пытаюсь создать представление этой таблицы, которая выводила бы только самую последнюю запись на идентификатор пользователя, давая мне значение" in "или" out", поэтому что-то вроде:
id user time io
2 9 1370931664 out
3 6 1370932128 out
5 12 1370933037 in
Я довольно близок до сих пор, но я понял, что представления не будут принимать субквери, что делает его намного сложнее. Ближайший запрос, который я получил, был :
select
`lms_attendance`.`id` AS `id`,
`lms_attendance`.`user` AS `user`,
max(`lms_attendance`.`time`) AS `time`,
`lms_attendance`.`io` AS `io`
from `lms_attendance`
group by
`lms_attendance`.`user`,
`lms_attendance`.`io`
но я получаю :
id user time io
3 6 1370932128 out
1 9 1370931664 out
5 12 1370933037 in
4 12 1370932128 out
что близко, но не идеально. Я знаю, что последняя группа не должна быть там, но без нее она возвращает самое последнее время, но не с относительным значением IO.
какие идеи? Спасибо!
8 ответов
запрос:
SELECT t1.*
FROM lms_attendance t1
WHERE t1.time = (SELECT MAX(t2.time)
FROM lms_attendance t2
WHERE t2.user = t1.user)
результат:
| ID | USER | TIME | IO |
--------------------------------
| 2 | 9 | 1370931664 | out |
| 3 | 6 | 1370932128 | out |
| 5 | 12 | 1370933037 | in |
решение, которое будет работать каждый раз:
SELECT t1.*
FROM lms_attendance t1
WHERE t1.id = (SELECT t2.id
FROM lms_attendance t2
WHERE t2.user = t1.user
ORDER BY t2.id DESC
LIMIT 1)
нет необходимости пытаться изобрести колесо, так как это распространено наибольшая-n-в-группе проблема. Очень мило решение представлено.
Я предпочитаю самое упрощенное решение (см. SQLFiddle, обновленный Justin's) без подзапросов (таким образом, прост в использовании в представлениях):
SELECT t1.*
FROM lms_attendance AS t1
LEFT OUTER JOIN lms_attendance AS t2
ON t1.user = t2.user
AND (t1.time < t2.time
OR (t1.time = t2.time AND t1.Id < t2.Id))
WHERE t2.user IS NULL
Это также работает в случае, когда есть две разные записи с одинаковым наибольшим значением в той же группе - благодаря трюк с (t1.time = t2.time AND t1.Id < t2.Id)
. Все Я делаю здесь является то, что в случае, когда две записи одного пользователя одновременно выбирается только один. На самом деле не имеет значения, если условие Id
или что - то еще-в основном любые критерии, которые гарантированно будут уникальными, сделают работу здесь.
на основе ответа @TMS мне нравится, потому что нет необходимости в подзапросах, но я думаю, что ommiting 'OR'
часть будет достаточно и гораздо проще понять и прочитать.
SELECT t1.*
FROM lms_attendance AS t1
LEFT JOIN lms_attendance AS t2
ON t1.user = t2.user
AND t1.time < t2.time
WHERE t2.user IS NULL
если вас не интересуют строки с нулевым временем, вы можете фильтровать их в WHERE
статья:
SELECT t1.*
FROM lms_attendance AS t1
LEFT JOIN lms_attendance AS t2
ON t1.user = t2.user
AND t1.time < t2.time
WHERE t2.user IS NULL and t1.time IS NOT NULL
уже решено, но только для записи другим подходом было бы создание двух представлений...
CREATE TABLE lms_attendance
(id int, user int, time int, io varchar(3));
CREATE VIEW latest_all AS
SELECT la.user, max(la.time) time
FROM lms_attendance la
GROUP BY la.user;
CREATE VIEW latest_io AS
SELECT la.*
FROM lms_attendance la
JOIN latest_all lall
ON lall.user = la.user
AND lall.time = la.time;
INSERT INTO lms_attendance
VALUES
(1, 9, 1370931202, 'out'),
(2, 9, 1370931664, 'out'),
(3, 6, 1370932128, 'out'),
(4, 12, 1370932128, 'out'),
(5, 12, 1370933037, 'in');
SELECT * FROM latest_io;
select b.* from
(select
`lms_attendance`.`user` AS `user`,
max(`lms_attendance`.`time`) AS `time`
from `lms_attendance`
group by
`lms_attendance`.`user`) a
join
(select *
from `lms_attendance` ) b
on a.user = b.user
and a.time = b.time
возможно, вы можете сделать группу по пользователю, а затем заказать по времени desc. Что-то вроде как ниже
SELECT * FROM lms_attendance group by user order by time desc;
это сработало для меня:
SELECT user, time FROM
(
SELECT user, time FROM lms_attendance --where clause
) AS T
WHERE (SELECT COUNT(0) FROM table WHERE user = T.user AND time > T.time) = 0
ORDER BY user ASC, time DESC