SQL не является традиционным языком программирования, на котором вы пишете последовательность инструкций в определенном порядке выполнения. Вместо этого SQL является «декларативным» языком, что означает, что, составляя SQL-запрос, вы указываете, какие данные ожидаете получить в результате запроса, но не указываете, как их получить.
Шесть операций: SELECT, FROM, WHERE, GROUP BY, HAVING и ORDER BY
На примерах мы объясним порядок выполнения шести наиболее распространенных операций или частей в запросе SQL. Поскольку база данных выполняет компоненты запроса в определенном порядке, разработчику полезно знать этот порядок. Это похоже на следование рецепту: нужно знать ингредиенты и что делать с ингредиентами, но также нужно знать, в каком порядке выполнять задания. Если база данных следует другому порядку операций, производительность запроса может резко снизиться.
База данных сотрудников
В этой статье мы будем работать с базой данных типичной компании, сотрудники которой распределены по различным отделам. Каждый сотрудник имеет идентификатор, имя, зарплату и принадлежит к отделу, как мы видим в следующих таблицах.
Образец таблицы EMPLOYEE:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT |
---|---|---|---|---|
100 | James | Smith | 78,000 | ACCOUNTING |
101 | Mary | Sexton | 82,000 | IT |
102 | Chun | Yen | 80,500 | ACCOUNTING |
103 | Agnes | Miller | 95,000 | IT |
104 | Dmitry | Komer | 120,000 | SALES |
Образец таблицы DEPARTMENT:
DEPT_NAME | MANAGER | BUDGET |
---|---|---|
ACCOUNTING | 100 | 300,000 |
IT | 101 | 250,000 |
SALES | 104 | 700,000 |
В этой статье мы также будем использовать частые SQL-запросы, используемые в компании: «Получить имена сотрудников, работающих в ИТ-отделе» или «Получить количество сотрудников в каждом отделе с зарплатой выше 80.000». Для каждого из этих запросов мы проанализируем порядок выполнения его компонентов.
Начнем с простого запроса на получение имен сотрудников, работающих в IT-отделе:
SELECT LAST_NAME, FIRST_NAME FROM EMPLOYEE WHERE DEPARTMENT = 'IT'
Сначала мы выполняем FROM EMPLOYEE, который извлекает эти данные:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT |
---|---|---|---|---|
100 | James | Smith | 78,000 | ACCOUNTING |
101 | Mary | Sexton | 82,000 | IT |
102 | Chun | Yen | 80,500 | ACCOUNTING |
103 | Agnes | Miller | 95,000 | IT |
104 | Dmitry | Komer | 120,000 | SALES |
Во-вторых, мы выполняем WHERE DEPARTMENT = ‘IT’, что сужает список:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT |
---|---|---|---|---|
101 | Mary | Sexton | 82,000 | IT |
103 | Agnes | Miller | 95,000 | IT |
Наконец, мы применяем SELECT FIRST_NAME, LAST_NAME, получая конечный результат запроса:
FIRST_NAME | LAST_NAME |
---|---|
Mary | Sexton |
Agnes | Miller |
Отлично! Завершив разбор первого запроса, мы можем сделать вывод, что порядок выполнения простых запросов с SELECT, FROM и WHERE следующий:
Изменения в порядке операций при добавлении ORDER BY
Предположим, ваш начальник получил отчет, основанный на запросе из предыдущего примера, и отклонил его, потому что имена сотрудников расположены не в алфавитном порядке. Чтобы исправить это, нужно добавить к предыдущему запросу ORDER BY:
SELECT LAST_NAME, FIRST_NAME FROM EMPLOYEE WHERE DEPARTMENT = 'IT' ORDER BY FIRST_NAME
Процесс выполнения этого запроса почти такой же, как и в предыдущем примере. Единственное изменение происходит в конце, когда обрабатывается запрос ORDER BY. Конечный результат этого запроса упорядочивает записи по FIRST_NAME, как показано ниже:
FIRST_NAME | LAST_NAME |
---|---|
Agnes | Miller |
Mary | Sexton |
Итак, если у нас есть SELECT с FROM, WHERE и ORDER BY, то порядок выполнения будет следующим:
Добавление в запрос условий GROUP BY и HAVING
В этом примере мы будем использовать запрос с GROUP BY. Предположим, мы хотим получить, сколько сотрудников в каждом отделе имеют зарплату выше 80 000, и хотим получить результат в порядке убывания по количеству людей в каждом отделе. Запрос для этой ситуации выглядит следующим образом:
SELECT DEPARTMENT, COUNT(*) FROM EMPLOYEES WHERE SALARY > 80000 GROUP BY DEPARTMENT ORDER BY COUNT(*) DESC
Опять же, сначала мы выполняем FROM EMPLOYEE, который извлекает эти данные:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT |
---|---|---|---|---|
100 | James | Smith | 78,000 | ACCOUNTING |
101 | Mary | Sexton | 82,000 | IT |
102 | Chun | Yen | 80,500 | ACCOUNTING |
103 | Agnes | Miller | 95,000 | IT |
104 | Dmitry | Komer | 120,000 | SALES |
Во-вторых, мы выполняем WHERE SALARY > 80000, что сужает выборку:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT |
---|---|---|---|---|
101 | Mary | Sexton | 82,000 | IT |
102 | Chun | Yen | 80,500 | ACCOUNTING |
103 | Agnes | Miller | 95,000 | IT |
104 | Dmitry | Komer | 120,000 | SALES |
В-третьих, применяется GROUP BY, создавая по одной записи для каждого отдельного значения в столбцах GROUP BY. В нашем примере мы создаем по одной записи для каждого отдельного значения в DEPARTMENT:
DEPARTMENT |
---|
ACCOUNTING |
IT |
SALES |
В-четвертых, мы применяем SELECT с COUNT(*), получая такой промежуточный результат:
DEPARTMENT | COUNT(*) |
---|---|
ACCOUNTING | 1 |
IT | 2 |
SALES | 1 |
Наконец, мы применяем ORDER BY, получая окончательный результат запроса:
DEPARTMENT | COUNT(*) |
---|---|
IT | 2 |
ACCOUNTING | 1 |
SALES | 1 |
Порядок выполнения в этом примере следующий:
В следующем примере мы добавим условие HAVING. HAVING не так часто используется в SQL, как другие условия, которые мы рассматривали до сих пор. Лучший способ описать HAVING — это то, что он похож на предложение WHERE для GROUP BY. Другими словами, это способ отфильтровать или отбросить некоторые группы записей, созданные с помощью GROUP BY.
Предположим, что теперь мы хотим получить все отделы, кроме отдела SALES, со средней зарплатой выше 80 000. Запрос для этой ситуации выглядит следующим образом:
SELECT DEPARTMENT FROM EMPLOYEES WHERE DEPARTMENT <> 'SALES' GROUP BY DEPARTMENT HAVING AVG(SALARY) > 80000
Опять же, сначала мы выполняем FROM EMPLOYEE, который извлекает эти данные:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT |
---|---|---|---|---|
100 | James | Smith | 78,000 | ACCOUNTING |
101 | Mary | Sexton | 82,000 | IT |
102 | Chun | Yen | 80,500 | ACCOUNTING |
103 | Agnes | Miller | 95,000 | IT |
104 | Dmitry | Komer | 120,000 | SALES |
Во-вторых, обрабатывается условие WHERE, исключающее записи SALES:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT |
---|---|---|---|---|
100 | James | Smith | 78,000 | ACCOUNTING |
101 | Mary | Sexton | 82,000 | IT |
102 | Chun | Yen | 80,500 | ACCOUNTING |
103 | Agnes | Miller | 95,000 | IT |
В-третьих, применяется GROUP BY, создавая следующие записи:
DEPARTMENT | AVG(SALARY) |
---|---|
ACCOUNTING | 79,250 |
IT | 88,500 |
В-четвертых, HAVING AVG(SALARY) > 80000 применяется для фильтрации группы записей, созданной с помощью GROUP BY:
DEPARTMENT | AVG(SALARY) |
---|---|
IT | 88,500 |
И наконец, применяется SELECT, в результате чего получается конечный результат запроса:
DEPARTMENT |
---|
IT |
Порядок выполнения в этом примере следующий:
Добавление нового оператора JOIN
В предыдущих примерах рассматривалась одна таблица. Давайте добавим вторую таблицу, используя оператор JOIN. Предположим, мы хотим получить фамилии и идентификаторы сотрудников, работающих в отделах с бюджетом более 275 000. Запрос для этой ситуации выглядит следующим образом:
SELECT EMPLOYEE_ID, LAST_NAME FROM EMPLOYEES JOIN DEPARTMENT ON DEPARTMENT = DEPT_NAME WHERE BUDGET > 275000
Опять же, сначала мы выполняем FROM EMPLOYEE, который извлекает эти данные:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT |
---|---|---|---|---|
100 | James | Smith | 78,000 | ACCOUNTING |
101 | Mary | Sexton | 82,000 | IT |
102 | Chun | Yen | 80,500 | ACCOUNTING |
103 | Agnes | Miller | 95,000 | IT |
104 | Dmitry | Komer | 120,000 | SALES |
Во-вторых, мы применяем условие JOIN, генерируя новый промежуточный результат, объединяющий обе таблицы:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT | DEPT_NAME | MANAGER | BUDGET |
---|---|---|---|---|---|---|---|
100 | James | Smith | 78,000 | ACCOUNTING | ACCOUNTING | 100 | 300,000 |
101 | Mary | Sexton | 82,000 | IT | IT | 101 | 250,000 |
102 | Chun | Yen | 80,500 | ACCOUNTING | ACCOUNTING | 100 | 300,000 |
103 | Agnes | Miller | 95,000 | IT | IT | 101 | 250,000 |
104 | Dmitry | Komer | 120,000 | SALES | SALES | 104 |
В-третьих, применяется функция WHERE BUDGET > 275000:
EMPLOYEE_ID | FIRST_NAME | LAST_NAME | SALARY | DEPARTMENT | DEPT_NAME | MANAGER | BUDGET |
---|---|---|---|---|---|---|---|
100 | James | Smith | 78,000 | ACCOUNTING | ACCOUNTING | 100 | 300,000 |
102 | Chun | Yen | 80,500 | ACCOUNTING | ACCOUNTING | 100 | 300,000 |
104 | Dmitry | Komer | 120,000 | SALES | SALES | 104 |
Наконец, выполняется SELECT EMPLOYEE_ID, LAST_NAME, выдавая конечный результат запроса:
EMPLOYEE_ID | LAST_NAME |
---|---|
100 | Smith |
102 | Yen |
104 | Komer |
Порядок выполнения в этом примере следующий:
Заключительные слова
В этой статье мы рассмотрели порядок выполнения SQL-запросов на примерах. Из этих примеров видно, что существует определенный порядок, но этот порядок может меняться в зависимости от того, какие пункты присутствуют в запросе. В качестве общего руководства можно сказать, что порядок выполнения следующий:
Однако если один из этих пунктов отсутствует, порядок выполнения будет другим. SQL — это простой язык начального уровня, но как только вы погрузитесь в него, вам предстоит изучить множество интересных концепций.
Возможно вам будет интересно: