У меня есть таблица ("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
Что близко, но не идеально. Я знаю, что этой последней группы не должно быть, но без нее она возвращает самое последнее время, но не с относительным значением ввода-вывода.
Любые идеи? Спасибо!
Ответы:
Запрос:
SQLFIDDLEExample
Результат:
Решение, которое будет работать каждый раз:
SQLFIDDLEExample
источник
Не нужно изобретать велосипед, так как это обычная проблема с наибольшим числом участников на группу . Представлено очень красивое решение .
Я предпочитаю наиболее упрощенное решение ( см. SQLFiddle, обновленный Justin's ) без подзапросов (что упрощает использование в представлениях):
Это также работает в случае, когда есть две разные записи с одинаковым наибольшим значением в одной и той же группе - благодаря уловке с
(t1.time = t2.time AND t1.Id < t2.Id)
. Все, что я здесь делаю, это чтобы убедиться, что в случае, когда две записи одного и того же пользователя имеют одинаковое время, выбирается только одна. На самом деле не имеет значения, являются ли критерииId
или что-то еще - в основном любые критерии, которые гарантированно уникальны, будут работать здесь.источник
t1.time < t2.time
а минимальноеt1.time > t2.time
- это противоположность моей первоначальной интуиции.t1.time < t2.time
применяется условие :-)WHERE t2.user IS NULL
немного странно. Какую роль играет эта линия?OR (t1.time = t2.time AND t1.Id < t2.Id))
раздел?Основываясь на ответе @TMS, мне он нравится, потому что нет необходимости в подзапросах, но я думаю, что пропуск
'OR'
части будет достаточно и намного проще для понимания и чтения.если вас не интересуют строки с нулевым временем, вы можете отфильтровать их в
WHERE
предложении:источник
OR
части - действительно плохая идея, если две записи могут иметь одно и то жеtime
.Уже решено, но для записи, другой подход - создать два представления ...
Нажмите здесь, чтобы увидеть его в действии на SQL Fiddle
источник
источник
join (select * from lms_attendance ) b
=join lms_attendance b
источник
Если вы используете MySQL 8.0 или выше, вы можете использовать оконные функции :
Запрос:
DBFiddleExample
Результат:
Преимущество, которое я вижу перед использованием решения, предложенного Джастином, заключается в том, что оно позволяет вам выбирать строку с самыми последними данными для каждого пользователя (или для идентификатора, или для чего-то еще) даже из подзапросов без необходимости в промежуточном представлении или таблице.
И если вы используете HANA, он также в ~ 7 раз быстрее: D
источник
Хорошо, это может быть либо взлом, либо подверженный ошибкам, но каким-то образом это тоже работает -
источник
Попробуйте этот запрос:
источник
id
иio
являетесь неагломерированными столбцами, которые не могут быть использованы вgroup by
.Возможно, вы можете сделать группу по пользователю, а затем упорядочить по времени по убыванию. Что-то вроде как ниже
источник
Это сработало для меня:
источник