Ответ
Да, активно использовал вложенные запросы (подзапросы) в различных сценариях. Подзапрос — это запрос, вложенный внутрь другого запроса (SELECT, INSERT, UPDATE, DELETE). Он может возвращать скалярное значение, список значений или целую таблицу.
Основные типы и примеры использования:
-
Скалярный подзапрос (в
SELECT,WHERE,HAVING). Возвращает одно значение.-- Найти всех пользователей, чей доход выше среднего по компании SELECT name, salary FROM employees WHERE salary > (SELECT AVG(salary) FROM employees); -
Подзапрос, возвращающий множество значений (с
IN,ANY,ALL,EXISTS).-- Найти товары, которые никогда не заказывались SELECT id, name FROM products p WHERE NOT EXISTS ( SELECT 1 FROM order_items oi WHERE oi.product_id = p.id ); -
Подзапрос в качестве производной таблицы (в
FROM). Результат подзапроса используется как временная таблица.-- Найти для каждого отдела его сотрудника с максимальной зарплатой SELECT d.name AS department, e.name AS employee, e.salary FROM departments d JOIN ( SELECT department_id, MAX(salary) as max_salary FROM employees GROUP BY department_id ) max_sal ON d.id = max_sal.department_id JOIN employees e ON e.department_id = max_sal.department_id AND e.salary = max_sal.max_salary;
Ключевые соображения и опыт:
-
Производительность: Коррелированные подзапросы (которые ссылаются на столбцы внешнего запроса) могут выполняться очень медленно для больших таблиц, так как они запускаются для каждой строки внешнего запроса. В таких случаях часто более эффективна замена на
JOIN.- Медленно (коррелированный):
SELECT * FROM users u WHERE (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) > 5; - Быстрее (через JOIN и GROUP BY):
SELECT u.* FROM users u JOIN orders o ON u.id = o.user_id GROUP BY u.id HAVING COUNT(*) > 5;
- Медленно (коррелированный):
-
Читаемость: Сложные многоуровневые подзапросы могут сильно ухудшать читаемость SQL. В современных СУБД часто предпочтительнее использовать CTE (Common Table Expressions,
WITHclause), которые структурируют запрос и делают его более понятным.WITH high_value_orders AS ( SELECT user_id, SUM(total) as order_sum FROM orders GROUP BY user_id HAVING SUM(total) > 10000 ) SELECT u.name, hvo.order_sum FROM users u JOIN high_value_orders hvo ON u.id = hvo.user_id; -
Возможности СУБД: Современные оптимизаторы запросов (в PostgreSQL, MySQL 8+, SQL Server) умеют очень хорошо "разворачивать" и оптимизировать подзапросы, иногда преобразуя их в те же
JOINна этапе построения плана выполнения. Всегда стоит проверять план запроса (EXPLAIN) для критичных по производительности операций.
В итоге, подзапросы — мощный инструмент, но их применение требует понимания их влияния на производительность и предпочтения в пользу JOIN или CTE в сложных случаях для поддержания чистоты и скорости кода.