Что такое запрос в SQL?
Запросом называют инструкцию системе управления базами данных, в которой описано что нужно сделать. Она состоит из одной строчки, хотя сложные длинные команды могут записывать в несколько строк для удобства чтения кода.
Команду на отображение имён пользователей с таблицы users, которым 30+ лет с сортировкой по имени в алфавитном порядке, можно записать двумя способами:
SELECT name, age FROM users WHERE age > 30 ORDER BY name;
или
SELECT name, age
FROM users
WHERE age > 30
ORDER BY name;
А теперь представьте более сложную инструкцию, записанную в одну строчку.
SELECT u.name, COUNT(o.id) AS order_count, SUM(o.total_amount) AS total_spent
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.status = 'completed'
GROUP BY u.name
HAVING COUNT(o.id) > 5
ORDER BY total_spent DESC;
Какой вариант кода легче понять?
Состав запросов.
- Ключевые слова — зарезервированные команды SQL (SELECT, FROM, WHERE и т.д.)
- Идентификаторы — имена таблиц, колонок, схем.
- Литералы — конкретные значения (строки, числа, даты).
- Операторы — символы для сравнения, арифметические и логические действия.
- Разделители — запятые, скобки, точки с запятой.
Их базовая структура включает до 7 команд:
- SELECT [модификаторы] список_колонок – ключевое слов.
- FROM источник_данных – указатель, идентификатор данных – с какой частью таблицы работать: номера, количество строк, например.
- [WHERE условия_фильтрации] – условие для фильтрации данных.
- [GROUP BY колонки_группировки] – условие группировки информации по столбцам.
- [HAVING условия_для_групп] – собирает группы по условию, применяют обычно со следующим оператором.
- [ORDER BY колонки_сортировки] – способ сортировки: по возрастания или в обратном порядке.
- [LIMIT количество_записей] – максимальное число первых n записей, если их в таблице больше указанного количества удовлетворяющих условия.
Две первые команды обязательны: SELECT и FROM, остальные – нет.
Пример:
SELECT
department_id, -- Выбираем столбец
COUNT(*) AS employee_count, -- Подсчет
AVG(salary) AS avg_salary -- Агрегатная функция среднего
FROM
employees -- Источник данных - таблица
WHERE
hire_date > '2024-03-11' -- Фильтр: сотрудники, принятые после указанной даты
GROUP BY
department_id -- Группировка по отделам
HAVING
COUNT(*) > 7 -- Фильтр групп: отделы с >7 сотрудниками
ORDER BY
avg_salary DESC -- Сортировка по убыванию средней зарплаты
LIMIT 5; -- Только топ-5 отдела
Ничего сложного, даже после беглого знакомства с SQL код становится читаемым и легко понимаемым, тем более он близок к естественным языкам и Python.
Классификация запросов
Команды делят по разным критериям.
Количество используемых таблиц
Исходя из числа задействованных таблиц:
Запросы к одной таблице – базовые операции с данными в конкретной структуре, сущности: выборка, редактирование, фильтрация, удаление, обновление, математические операции: SELECT, GROUP BY, WHERE.
Многотабличные – объединяют содержимое двух и более таблиц при помощи операций JOIN.
- INNER JOIN: возвращает строки, для которых есть совпадения в обеих таблицах.
- LEFT JOIN: возвращает строки из левой таблицы и совпадающие строки из правой. Если совпадений нет, правая часть содержит NULL.
- RIGHT JOIN: аналогично LEFT JOIN, но возвращает все строки из правой таблицы.
- FULL JOIN: возвращает строки, когда есть совпадение в одной из таблиц.
Пример работы многотабличного SQL-запроса: берёт сотрудников из таблицы employees соединяет с таблицей departments по общему полю таблиц (3 с первой и 1 со второй) department_id и возвращает список сотрудников с общим отделом.
SELECT -- Начало выборки данных
e.employee_id, -- ID сотрудника из таблицы employees
e.first_name, -- Имя сотрудника
e.last_name, -- Фамилия сотрудника
d.department_name -- Название отдела из таблицы departments
FROM -- Указываем основную таблицу для выборки
employees e -- Таблица сотрудников с алиасом 'e' для удобства
INNER JOIN -- Тип соединения таблиц (внутреннее соединение)
departments d -- Таблица отделов с алиасом 'd'
ON -- Условие соединения таблиц
e.department_id = d.department_id; -- Связь по полю department_id
Подзапросы или вложенные SELECT-запросы. Бывают:
Корреляционными – ссылаются на колонки из внешнего запроса и выполняются для каждой строки внешнего запроса. Это делает их менее эффективными, но иногда незаменимыми для решения сложных задач.
--Поиск последнего заказа каждого клиента:
SELECT
customer_id,
order_id,
order_date,
total_amount
FROM orders o1
WHERE order_date = (
SELECT MAX(order_date)
FROM orders o2
WHERE o2.customer_id = o1.customer_id
);
Предикатными – используются в условиях WHERE или HAVING с предикатами IN, ANY, ALL, EXISTS. Они не коррелированы с внешним запросом, выполняются один раз, решают сложные аналитические задачи.
— Поиск продуктов, которые были заказаны в количестве больше среднего:
SELECT
p.product_id,
p.product_name,
p.price
FROM
products p
WHERE
p.product_id IN (
-- Находим товары, в данном случае, заказанные в количестве выше среднего
SELECT
oi.product_id
FROM
order_items oi
WHERE
-- Условие: количество в заказе больше среднего для этого товара
oi.quantity > (
-- Подзапрос для расчета среднего количества товара в заказах
SELECT
AVG(quantity)
FROM
order_items
WHERE
product_id = oi.product_id
)
GROUP BY
oi.product_id
HAVING
-- Оставляем только товары с более чем 5 такими заказами
COUNT(*) > 5
);
Выделяют 5 групп запросов, которые отвечают за определённые аспекты работы с базой данных.
DDL
Data Definition Language – определение данных. Включает основные команды для создания, изменения и удаления структуры базы данных: таблиц, индексов, представлений, схем и других объектов.
CREATE – создание.
— Простой таблицы.
CREATE TABLE employees (
employee_id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
hire_date DATE,
salary DECIMAL(10,2),
department_id INT,
FOREIGN KEY (department_id) REFERENCES departments(department_id)
);
— Таблицы с дополнительными ограничениями.
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT NOT NULL,
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
total_amount DECIMAL(12,2) CHECK (total_amount > 0),
status ENUM('pending', 'processing', 'completed', 'cancelled')
);
— Обычного индекса.
CREATE INDEX idx_employee_email ON employees(email);
— Составного индекса.
CREATE INDEX idx_order_customer_date ON orders (customer_id, order_date);
ALTER – изменение структуры, ADD – добавление.
— Добавление новой колонки
ALTER TABLE employees
ADD COLUMN phone VARCHAR(20);
— Изменение типа данных колонки
ALTER TABLE employees
MODIFY COLUMN salary DECIMAL(12,2);
—Переименование колонки
ALTER TABLE employees
RENAME COLUMN hire_date TO employment_date;
— Добавление ограничения
ALTER TABLE employees
RENAME COLUMN hire_date TO employment_date;
DROP — удаление объектов.
— Таблицы
DROP TABLE temp_data;
— Индекса
DROP INDEX idx_employee_email;
— Представления
DROP VIEW employee_summary;
— Базы данных
DROP DATABASE test_database;
ВВД концентрируются на содержимом базы данных, её таблиц. С деланные с их помощью изменения невозможно откатить без резервной копии.
DML
Data Manipulation Language – манипуляции с данными: изменение, обновление, удаление, слияние.
INSERT — добавление.
— Простая вставка
INSERT INTO employees (first_name, last_name, email, hire_date, salary, department_id)
VALUES (Петр, 'Иванов', petr.ivanov@company.com', '2025-09-12', 65000.00, 1);
— Множественная вставка
INSERT INTO products (name, price, category) VALUES
('Laptop', 1999.99, 'Electronics'), ('Mouse', 26, 'Electronics'), ('Keyboard', 45.50, 'Electronics');
UPDATE – обновление.
— Обновление одной записи
UPDATE employees SET salary = 7000.00, department_id = 2 WHERE employee_id = 1;
DELETE – удаление.
— Удаляет конкретные записи из таблицы
DELETE FROM orders WHERE order_date < ‘2024-11-10’ AND status = ‘cancelled’;
DML, в отличие от DDL-запросов, которые описывают структуру баз данных, работают с её содержимым на более низком уровне.
DCL
Data Control Language – запросы управления доступом.
GRANT – предоставление прав.
— На чтение таблицы.
GRANT SELECT ON employees TO user_analyst;
— На базу данных (все привилегии)
GRANT ALL PRIVILEGES ON company_db.* TO admin_user;
REVOKE – отзыв прав.
— На обновление данных.
REVOKE UPDATE ON employees FROM junior_developer;
— Отзыв всех прав на таблицу.
REVOKE ALL PRIVILEGES ON sensitive_data FROM temp_user;
— Создание нового пользователя
CREATE USER ‘new_employee’@’localhost’ IDENTIFIED BY ‘secure_pass’;
— Изменение пароля пользователя
ALTER USER ‘existing_user’@’localhost’ IDENTIFIED BY ‘new_pass’;
DCL фокусируются на управлении правами пользователей, чем минимизирует риски несанкционированного доступа, изменения структуры, содержимого хранилища.
TCL
Transaction Control Language или запросы управления транзакциями.
TCL предлагает команды для управления транзакциями – логическими единицами работы с базой данных.
BEGIN/START TRANSACTION — начало транзакции.
— Явное начало транзакции
BEGIN TRANSACTION;
—Второй вариант
START TRANSACTION;
COMMIT — подтверждение транзакций.
BEGIN TRANSACTION;
INSERT INTO accounts (account_id, balance) VALUES (1001, 1000.00);
— Подтверждение всех изменений
COMMIT;
ROLLBACK – откат транзакции.
BEGIN TRANSACTION;
UPDATE products SET price = price * 2;
SAVEPOINT – создание точки сохранения.
BEGIN TRANSACTION;
— Создание нового клиента
INSERT INTO customers (name, email) VALUES ('Test User', 'test@example.com');
SAVEPOINT customer_created;
TCL-запросы управляют транзакциями: начинают, фиксируют и подтверждают их.
DQL
Data Query Language отвечают за извлечения данных из БД. Единственная команда этой категории – SELECT, но она обладает огромной функциональностью и гибкостью.
— Выбор всех колонок из таблицы
SELECT * FROM employees;
—Выбор конкретных колонок
SELECT first_name, last_name, email FROM employees;
—Условная выборка
SELECT * FROM employees WHERE department = 'IT' AND salary > 50000;
—Подсчет количества сотрудников по департаментам
SELECT
department,
COUNT(*) as employee_count,
AVG(salary) as avg_salary,
MAX(salary) as max_salary
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;
Технически DQL относят к подмножеству DML, но часто выделяют в отдельную категорию из-за крайней важности – SELECT используют чаще любой другой команды.
Сложные запросы
Что делать новичку, когда появляется необходимость составлять сложные запросы?
Второй вариант — самый практичный, третий — наиболее простой и быстрый. Если решите применять нейросети для генерирования SQL-запросов, описывайте задачу как можно подробнее, например:
Напиши сложный SQL-запрос: нужно определить суммарную зарплату молодых сотрудников, принятых начиная с 2024 года, сгруппировав с по отделам. Дополнительные сведения:
- отдел — столбец называется department ;
- столбец с зарплатой — это salary;
- имена сотрудников — name;
- дата принятия на работу — date_working.
В итоге получите готовый запрос:
WITH
— Фильтрация сотрудников, принятых с 2024 года
recent_employees AS (
SELECT
department,
name,
salary,
date_working,
EXTRACT(YEAR FROM date_working) AS hire_year
FROM
employees
WHERE
date_working >= '2024-01-01'
),
— Расчет статистики по отделам
department_stats AS (
SELECT
department,
COUNT(*) AS employee_count,
SUM(salary) AS total_salary,
ROUND(AVG(salary), 2) AS avg_salary,
MAX(salary) AS max_salary,
MIN(salary) AS min_salary,
ROUND(STDDEV(salary), 2) AS salary_stddev
FROM
recent_employees
GROUP BY
department
),
— Расчет общего среднего по компании
company_stats AS (
SELECT
AVG(salary) AS company_avg_salary,
SUM(salary) AS company_total_salary
FROM
recent_employees
)
— Итоговый отчет с расширенной аналитикой
SELECT
ds.department,
ds.employee_count,
ds.total_salary,
ds.avg_salary,
ds.max_salary,
ds.min_salary,
ds.salary_stddev,
— Процент от общих расходов на зарплаты
ROUND((ds.total_salary / cs.company_total_salary) * 100, 2) AS salary_percentage,
— Сравнение со средним по компании
ROUND((ds.avg_salary / cs.company_avg_salary) * 100, 2) AS avg_salary_comparison,
— Список сотрудников в отделе
(SELECT STRING_AGG(name, ', ' ORDER BY salary DESC)
FROM recent_employees re
WHERE re.department = ds.department) AS employees_list,
— Флаг высокооплачиваемых отделов
CASE
WHEN ds.avg_salary > cs.company_avg_salary * 1.2 THEN 'Высокий'
WHEN ds.avg_salary > cs.company_avg_salary THEN 'Выше среднего'
WHEN ds.avg_salary < cs.company_avg_salary THEN 'Ниже среднего'
ELSE 'Средний'
END AS salary_level
FROM
department_stats ds
CROSS JOIN
company_stats cs
ORDER BY
ds.total_salary DESC,
ds.avg_salary DESC;
Итоговый результат всегда можно подкорректировать самому или попросить сделать это нейронную сеть.
Таблица SQL-запросов
Основные операторы для работы с базами данных мы вынесли в таблицу, которую можно использовать как шпаргалку для начинающих.
Категория | Тип запроса/функции | Примеры SQL-запросов | Описание |
Основные | SELECT | SELECT name, age FROM users | Выбор данных из таблицы |
INSERT | INSERT INTO users (name, age) VALUES (‘Иван’, 30) | Добавление новых записей | |
UPDATE | UPDATE users SET age=31 WHERE name=’Иван’ | Обновление записей | |
DELETE | DELETE FROM users WHERE age > 100 | Удаление записей | |
Строковые | UPPER() | SELECT UPPER(name) FROM users | Преобразование в верхний регистр |
LOWER() | SELECT LOWER(email) FROM contacts | Преобразование в нижний регистр | |
CONCAT() | SELECT CONCAT(first_name, ‘ ‘, last_name) FROM employees | Объединение строк | |
SUBSTRING() | SELECT SUBSTRING(phone, 1, 3) FROM clients | Извлечение части строки | |
TRIM() | SELECT TRIM(address) FROM locations | Удаление пробелов с обеих сторон | |
Дата/время | NOW() | SELECT NOW() AS current_datetime | Текущая дата и время |
CURDATE() | SELECT CURDATE() AS today | Текущая дата | |
CURTIME() | SELECT CURTIME() AS current_time | Текущее время | |
YEAR() | SELECT YEAR(birth_date) FROM persons | Извлечение года из даты | |
MONTH() | SELECT MONTH(created_at) FROM orders | Извлечение месяца (1-12) | |
DAY() | SELECT DAY(delivery_date) FROM shipments | Извлечение дня месяца | |
DATE_FORMAT() | SELECT DATE_FORMAT(date, ‘%d.%m.%Y’) FROM events | Форматирование даты | |
DATEDIFF() | SELECT DATEDIFF(end_date, start_date) FROM projects | Разница между датами в днях | |
Агрегатные функции | COUNT() | SELECT COUNT(*) FROM users | Подсчёт количества строк |
SUM() | SELECT SUM(salary) FROM employees | Сумма значений | |
AVG() | SELECT AVG(price) FROM products | Среднее значение | |
Соединения | JOIN | SELECT u.name, o.date FROM users u JOIN orders o ON u.id=o.user_id | Объединение таблиц |
SQL для работы с данными использует запросы или команды. Каждая из них нацелена на совершение действий с информацией, её структурой или правами доступа.