3.07. Другие операции в SQL
Разработчику
Аналитику
Тестировщику
Архитектору
Инженеру
Другие операции в SQL
Но SQL не ограничивается вышеуказанными командами. Дополнительные операции охватывают работу с таблицами, колонками, а также более продвинутыми задачами.
LIMIT
LIMIT — это ключевое слово в SQL, которое используется для ограничения количества строк, возвращаемых запросом. Оно полезно, когда нужно получить только определенное число строк из результата запроса, например, топ-N записей или выборку для пагинации.
SELECT * FROM users LIMIT 10;
Порой требуется получить только часть результатов — например, для постраничного вывода или отладки. Синтаксис может варьироваться в зависимости от диалекта SQL: в PostgreSQL и MySQL LIMIT n указывает максимальное число строк; в стандарте SQL и в некоторых других СУБД, таких как SQL Server, используется конструкция TOP или OFFSET ... FETCH. В SQLite и MySQL LIMIT также поддерживает смещение: LIMIT offset, count или LIMIT count OFFSET offset.
Фильтрация
★ Фильтрация данных – одна из самых важных операций в SQL, позволяет выбирать только нужные данные из таблиц. Оператор WHERE используется для указания условий отбора записей.
Примеры простых условий:
-- Выбрать всех пользователей старше 25 лет
SELECT * FROM users WHERE age > 25;
-- Выбрать товары с ценой от 100 до 500 рублей
SELECT * FROM products WHERE price BETWEEN 100 AND 500;
-- Выбрать заказы, сделанные сегодня
SELECT * FROM orders WHERE order_date = CURRENT_DATE;
Операторы SQL
Основные операторы в SQL сравнительные и логические. Рассмотрим их в таблице:
| Оператор | Описание | Пример |
|---|---|---|
= | Равно | WHERE age = 30 |
<> или != | Не равно | WHERE status <> 'active' |
> | Больше | WHERE price > 1000 |
< | Меньше | WHERE rating < 3.5 |
>= | Больше или равно | WHERE quantity >= 10 |
<= | Меньше или равно | WHERE age <= 18 |
BETWEEN | В диапазоне (включительно) | WHERE price BETWEEN 50 AND 100 |
IN | В списке значений | WHERE id IN (1, 5, 10) |
NOT IN | Не в списке значений | WHERE country NOT IN ('US', 'UK') |
IS NULL | Проверка на NULL | WHERE email IS NULL |
IS NOT NULL | Проверка на не-NULL | WHERE phone IS NOT NULL |
AND | И | WHERE country = 'Russia' AND age > 25; |
OR | ИЛИ | WHERE price < 100 OR price > 1000; |
NOT | НЕ | WHERE NOT status = 'cancelled'; |
LIKE | Похоже на % - любое количество символов, _ - ровно один символ | WHERE name LIKE 'Ан%'; WHERE email LIKE '%@gmail.com'; WHERE name LIKE '____'; |
Сортировка
★ Сортировка – ключевая операция, которая сортирует результаты запроса по указанным столбцам (по возрастанию или убыванию), путём выполнения ORDER BY:
SELECT column1, column2
FROM table_name
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC];
ASC (по умолчанию) – сортировка по возрастанию (A-Z, 0-9);
SELECT name, salary FROM employees ORDER BY salary ASC;
DESC – по убыванию (Z-A, 9-0).
SELECT name, salary FROM employees ORDER BY salary DESC;
Группировка
★ Группировка объединяет строки с одинаковыми значениями в группы – GROUP BY. Для каждой группы может быть вычислено агрегированное значение с использованием функций, таких как COUNT, SUM, AVG, MIN, MAX. Это агрегатные функции - о них мы поговорим отдельно.
Структура запроса с группировкой:
SELECT column, AGG_FUNC(expression)
FROM table
WHERE condition
GROUP BY column
HAVING group_condition
ORDER BY column;
Предложение GROUP BY определяет, по каким признакам производится объединение строк. Все уникальные комбинации значений в указанных столбцах формируют отдельную группу.
SELECT department_id, COUNT(*) AS employee_count
FROM employees
GROUP BY department_id;
Запрос возвращает количество сотрудников в каждом отделе.
Если в списке выборки присутствуют неагрегированные столбцы, они должны входить в GROUP BY. В противном случае запрос будет некорректным (за исключением некоторых диалектов, допускающих функциональную зависимость).
Можно группировать по нескольким столбцам:
SELECT department_id, job_title, AVG(salary)
FROM employees
GROUP BY department_id, job_title;
Это позволяет получить среднюю зарплату по каждой должности внутри отдела.
Кроме этого, фильтрация может быть не только через WHERE, но и через HAVING. Предложение HAVING используется для фильтрации групп, в отличие от WHERE, которое фильтрует отдельные строки до группировки.
WHERE применяется до GROUP BY — фильтрует строки таблицы.
HAVING применяется после GROUP BY — фильтрует результаты по агрегированным значениям.
-- Отделы, где средняя зарплата > 100000
SELECT department, AVG(salary) as avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 100000;
-- Только активные сотрудники (фильтр до группировки)
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
WHERE status = 'active'
GROUP BY department_id
HAVING AVG(salary) > 80000; -- Фильтр по средней зарплате (после группировки)
Здесь:
WHERE status = 'active' исключает уволенных до формирования групп.
HAVING AVG(salary) > 80000 оставляет только те отделы, где средняя зарплата превышает 80 000.
В HAVING можно использовать агрегатные функции (AVG, SUM, COUNT и т.д.), так как они рассчитываются на уровне групп. Строки с NULL в столбце группировки формируют отдельную группу. Все NULL значения считаются равными друг другу в контексте GROUP BY. Некоторые СУБД поддерживают расширенные формы группировки:
GROUP BY ROLLUP(...)— формирует итоговые строки по иерархии.GROUP BY CUBE(...)— все возможные комбинации группировок.
Вложенные запросы (подзапросы)
Вложенный запрос — это SQL-выражение, встроенное в другое выражение (обычно в SELECT, FROM, WHERE или HAVING). Подзапрос выполняется первым, и его результат используется во внешнем запросе.
Классификация подзапросов
Скалярный подзапрос
Возвращает ровно одно значение (одну строку и один столбец). Может использоваться в списке выборки или условиях.
Пример:
SELECT name, salary,
(SELECT AVG(salary) FROM employees) AS avg_salary
FROM employees;
Здесь подзапрос возвращает среднюю зарплату по всем сотрудникам и дублирует её в каждой строке результата.
Строчный подзапрос
Возвращает одну строку с несколькими столбцами. Используется, например, при сравнении составных значений.
Пример:
SELECT * FROM employees
WHERE (name, salary) = (
SELECT name, salary FROM employees
WHERE id = 101
);
Табличный подзапрос
Возвращает набор строк и столбцов. Может использоваться в предложении FROM или WHERE.
Пример:
SELECT e.name, e.salary
FROM (SELECT * FROM employees WHERE salary > 50000) AS e;
Подзапрос формирует временную таблицу «e» с сотрудниками, получающими более 50 000.
Подзапросы с оператором ALL
Оператор ALL используется для сравнения значения с каждым элементом результата подзапроса. Условие считается истинным, только если оно выполняется для всех значений.
Пример:
SELECT name, salary
FROM employees
WHERE salary > ALL (
SELECT salary FROM employees WHERE department_id = 5
);
Запрос возвращает сотрудников, чья зарплата выше любой зарплаты в отделе 5 (то есть выше максимальной в этом отделе).
Аналогичный результат можно получить с помощью MAX, но ALL полезен в контексте обобщённых условий.
Многостолбцовые подзапросы
Многостолбцовые подзапросы позволяют сравнивать несколько столбцов одновременно. Часто используются с операторами IN, EXISTS, =, >, < и ALL.
Пример:
SELECT * FROM employees
WHERE (department_id, salary) IN (
SELECT department_id, MAX(salary)
FROM employees
GROUP BY department_id
);
Запрос находит сотрудников с максимальной зарплатой в каждом отделе.
Коррелированные и некоррелированные подзапросы
Некоррелированный подзапрос — выполняется независимо от внешнего запроса. Его можно вычислить один раз.
Пример:
SELECT name FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
Коррелированный подзапрос — зависит от внешнего запроса и выполняется для каждой строки внешнего результата. Содержит ссылки на столбцы из внешнего запроса.
Пример:
SELECT e1.name, e1.salary, e1.department_id
FROM employees e1
WHERE e1.salary = (
SELECT MAX(e2.salary)
FROM employees e2
WHERE e2.department_id = e1.department_id
);
Для каждого сотрудника (e1) подзапрос находит максимальную зарплату в его отделе. Затем проверяется, равна ли зарплата сотрудника этому максимуму.
Такой подход позволяет находить топовых сотрудников по зарплате в каждом отделе, но требует осторожности из-за потенциальной нагрузки на производительность.