Будучи студентом бакалавриата, мне приходилось писать немало операторов 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 в соответствии с заданной спецификацией сортировки. На самом деле, если вам нужна дополнительная информация о запросе, раздел Назначение в документации подробно описывает запрос.