Какие бывают типы подзапросов?sql-10

Подзапросы (subqueries) классифицируются по нескольким критериям. Вот основные типы с примерами:

1. По месту использования в основном запросе

a) Подзапросы в WHERE

SELECT product_name
FROM products
WHERE category_id IN (
    SELECT category_id
    FROM categories
    WHERE is_active = 1
);

b) Подзапросы в FROM

SELECT dept.name, emp_stats.avg_salary
FROM departments dept
JOIN (
    SELECT department_id, AVG(salary) as avg_salary
    FROM employees
    GROUP BY department_id
) emp_stats ON dept.id = emp_stats.department_id;

c) Подзапросы в SELECT

SELECT
    name,
    salary,
    (SELECT AVG(salary) FROM employees) as company_avg_salary
FROM employees;

d) Подзапросы в HAVING

SELECT department_id, AVG(salary) as avg_salary
FROM employees
GROUP BY department_id
HAVING AVG(salary) > (
    SELECT AVG(salary)
    FROM employees
);

2. По типу возвращаемых данных

a) Скалярные

SELECT name
FROM employees
WHERE salary = (
    SELECT MAX(salary)
    FROM employees
);

b) Строковые

SELECT *
FROM products
WHERE (category_id, price) = (
    SELECT category_id, MAX(price)
    FROM products
    GROUP BY category_id
    LIMIT 1
);

c) Колонные

SELECT name
FROM customers
WHERE id IN (
    SELECT customer_id
    FROM orders
    WHERE amount > 1000
);

d) Табличные

SELECT *
FROM (
    SELECT department_id, COUNT(*) as emp_count
    FROM employees
    GROUP BY department_id
) dept_stats
WHERE emp_count > 5;

3. По зависимости от внешнего запроса

a) Независимые

SELECT name
FROM products
WHERE price > (
    SELECT AVG(price)
    FROM products
);

b) Коррелированные

SELECT e.name
FROM employees e
WHERE salary > (
    SELECT AVG(salary)
    FROM employees
    WHERE department_id = e.department_id
);

4. По операторам сравнения

a) С IN/NOT IN

SELECT name
FROM employees
WHERE id IN (
    SELECT manager_id
    FROM departments
);

b) С EXISTS/NOT EXISTS

SELECT d.department_name
FROM departments d
WHERE EXISTS (
    SELECT 1
    FROM employees e
    WHERE e.department_id = d.department_id
    AND e.salary > 100000
);

c) С ANY/SOME/ALL

SELECT name, salary
FROM employees
WHERE salary > ALL (
    SELECT salary
    FROM employees
    WHERE department = 'Support'
);

5. Рекурсивные подзапросы

WITH RECURSIVE org_hierarchy AS (
    -- Базовый случай
    SELECT id, name, manager_id, 1 as level
    FROM employees
    WHERE manager_id IS NULL

    UNION ALL

    -- Рекурсивная часть
    SELECT e.id, e.name, e.manager_id, h.level + 1
    FROM employees e
    JOIN org_hierarchy h ON e.manager_id = h.id
)
SELECT * FROM org_hierarchy;

6. Общие табличные выражения

WITH regional_sales AS (
    SELECT region, SUM(amount) as total_sales
    FROM orders
    GROUP BY region
),
top_regions AS (
    SELECT region
    FROM regional_sales
    WHERE total_sales > 1000000
)
SELECT * FROM top_regions;

Резюмируем

Основные типы подзапросов:

  1. По расположению: WHERE, FROM, SELECT, HAVING
  2. По возвращаемым данным: скалярные, строковые, колонные, табличные
  3. По зависимости: независимые и коррелированные
  4. По операторам: IN, EXISTS, ANY/ALL
  5. Специальные: рекурсивные, CTE

Ключевые рекомендации:

  • Коррелированные подзапросы могут быть медленными - проверяйте через EXPLAIN
  • Для больших наборов данных EXISTS обычно эффективнее IN
  • CTE улучшают читаемость сложных запросов
  • Всегда проверяйте возможность переписать подзапрос как JOIN

Правильное использование подзапросов - признак профессионального владения SQL.