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


















