WITH в Oracle SQL — как писать читаемые подзапросы

🟢WITH в Oracle SQL. Введение

Оператор WITH, также известный как Common Table Expression (CTE), позволяет определить временное имя подзапроса, которое можно использовать в основном запросе. Это особенно удобно, когда:

  • Запрос слишком сложный и громоздкий

  • Один и тот же подзапрос используется несколько раз

  • Нужно сделать SQL более читаемым и модульным


🔤 Написание

sql
WITH имя_подзапроса AS (
SELECT ...
)
SELECT ...
FROM имя_подзапроса;

🧮 Пример:

sql
WITH recent_orders AS (
SELECT * FROM orders WHERE order_date >= SYSDATE - 30
)
SELECT customer_id, COUNT(*)
FROM recent_orders
GROUP BY customer_id;

🔄 Где часто используется

  • В отчётах

  • В аналитических запросах

  • Для модульного подхода к сложным SQL

  • Для повторного использования результатов подзапроса

  • В рекурсивных запросах (рекурсивные CTE)


🧪 10 Примеров использования WITH с пояснениями

1️⃣ Базовый CTE

sql
WITH top_salaries AS (
SELECT * FROM employees WHERE salary > 10000
)
SELECT name FROM top_salaries WHERE department_id = 50;

Определили фильтр, использовали его повторно.


2️⃣ Несколько подзапросов в одном WITH

sql
WITH a AS (SELECT * FROM table_a),
b AS (SELECT * FROM table_b)
SELECT * FROM a JOIN b ON a.id = b.id;

Модульная структура запросов.


3️⃣ Использование WITH перед JOIN

sql
WITH sales_2024 AS (
SELECT * FROM sales WHERE EXTRACT(YEAR FROM sale_date) = 2024
)
SELECT p.product_name, s.amount
FROM products p
JOIN sales_2024 s ON p.product_id = s.product_id;

Фильтруем год только один раз.


4️⃣ CTE с агрегацией

sql
WITH dept_avg AS (
SELECT department_id, AVG(salary) AS avg_sal
FROM employees
GROUP BY department_id
)
SELECT * FROM dept_avg WHERE avg_sal > 5000;

Упрощённая агрегация.


5️⃣ CTE + оконная функция

sql
WITH ranked_emps AS (
SELECT *, RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rnk
FROM employees
)
SELECT * FROM ranked_emps WHERE rnk = 1;

Находим топ-сотрудников в каждом отделе.


6️⃣ Вложенные CTE

sql
WITH base AS (
SELECT * FROM employees
),
filtered AS (
SELECT * FROM base WHERE salary > 10000
)
SELECT COUNT(*) FROM filtered;

Многоуровневая очистка данных.


7️⃣ Рекурсивный CTE (иерархия)

sql
WITH org_chart (emp_id, manager_id, level) AS (
SELECT employee_id, manager_id, 1
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.manager_id, o.level + 1
FROM employees e
JOIN org_chart o ON e.manager_id = o.emp_id
)
SELECT * FROM org_chart;

Вывод иерархии сотрудников.


8️⃣ Использование CTE с временными расчётами

sql
WITH last_week AS (
SELECT * FROM orders WHERE order_date >= TRUNC(SYSDATE) - 7
)
SELECT COUNT(*) FROM last_week;

Избегаем повторения WHERE.


9️⃣ CTE с DELETE (через MERGE)

sql
WITH to_delete AS (
SELECT id FROM customers WHERE status = 'inactive'
)
DELETE FROM customers WHERE id IN (SELECT id FROM to_delete);

Удаление с использованием фильтра через CTE.


🔟 Объединение нескольких уровней анализа

sql
WITH sales_by_day AS (
SELECT TRUNC(sale_date) AS day, SUM(amount) AS total
FROM sales
GROUP BY TRUNC(sale_date)
),
daily_avg AS (
SELECT AVG(total) AS avg_amount FROM sales_by_day
)
SELECT * FROM daily_avg;

Чистая и понятная аналитика.


🧩 Заключение

Оператор WITH превращает сложные SQL-запросы в читабельные, модульные и масштабируемые конструкции. Это один из самых мощных инструментов в арсенале SQL-разработчика.

💡 Запомни:

  • WITH создаёт временное имя для подзапроса

  • Может содержать один или несколько CTE

  • Используется с SELECT, а также совместно с DELETE, UPDATE, MERGE

  • Поддерживает рекурсию

  • Повышает читаемость и производительность


🔜 Следующая статья:

RETURNING INTO в Oracle SQL — как получить значения после INSERT


Понравилась статья? Поделиться с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии