Будучи студентом бакалавриата, мне приходилось писать немало операторов SQL. Каким бы полезным это ни было, я не осознавал количества ограничений и различий, которые у меня были бы при написании запросов для работы. Хотя простые операторы select идентичны (или почти идентичны), более сложные запросы, использующие агрегаты и другие функции, сильно отличаются от использования MySQL для класса.
Например, на днях мне поручили написать запрос, который мог бы получить идентификатор человека, дату первого входа и дату последнего входа из таблиц со следующей схемой.
Всякий раз, когда пользователь успешно входил в систему, он добавлял строку в таблицу Person Previous Logins
с идентификатором человека и текущей датой и временем входа в систему. Следовательно, размер этой таблицы был довольно большим, поэтому извлечение всех записей, а затем получение первой и последней было неоптимальным решением.
Оттуда я начинаю думать о возможных способах, которыми мы можем легко получить наши результаты в формате Person ID | First Login Date | Last Login Date.
Это было необходимо для формы, которую я создавал, где пользователь мог видеть, когда другие пользователи входили в систему впервые и в последний раз. Сначала решение казалось простым достаточно, я мог бы просто получить первый столбец таблицы, отсортировав его по дате, и сделать то же самое, отсортировав его другим способом. Результатом этой попытки стал следующий запрос:
( SELECT * FROM PersonPreviousLogins WHERE PersonID=X ORDER BY login_date ASC LIMIT 1 ) UNION ( SELECT * FROM PersonPreviousLogins WHERE PersonID=X ORDER BY login_date DESC LIMIT 1 )
Этот первоначальный запрос дал полезные результаты:
LoginDate 8/25/2015 10:14:47 AM 1/18/2017 3:38:10 PM
Где первая строка была первым логином, а последняя строка — вторым логином. Это было здорово, однако я искал что-то, что поместило бы эту информацию в столбец вместе с идентификатором человека. Итак, немного покопавшись, наткнулся на сводные таблицы. Однако это решение было довольно громоздким, что привело меня к другому запросу:
select ID, max(date) keep (dense_rank first order by date) first_date, max(date) keep (dense_rank last order by date) last_date from PersonPreviousLogins group by ID
Это дало именно те результаты, которые я искал! Таким образом, это запрос, с которым я пошел.
Если вам интересно, откуда я беру информацию, я использую Документацию Oracle 10g Database SQL. На этой странице представлена информация о функциях FIRST
и LAST
aggregate/analytic. Эти функции воздействуют на набор значений из набора строк, которые ранжируются как FIRST
или LAST
в соответствии с заданной спецификацией сортировки. На самом деле, если вам нужна дополнительная информация о запросе, раздел Назначение в документации подробно описывает запрос.