Пошук уроків, статей та іншого контенту
Запит усередині запиту та іменовані тимчасові результати через WITH — коли й навіщо їх використовувати.
Підзапит (subquery) — SELECT, вкладений усередину іншого запиту, результат якого використовується як частина зовнішнього — наприклад, у WHERE для порівняння зі списком значень чи в FROM як тимчасова, обчислена на льоту таблиця:
-- Користувачі, що зробили хоча б одне замовлення дорожче 1000
SELECT name FROM users
WHERE id IN (
SELECT user_id FROM orders WHERE total > 1000
);Конструкція WITH дозволяє дати підзапиту ім'я й винести його перед основним запитом — той самий результат, що й вкладений підзапит, але значно читабельніший для складніших, багатоступеневих запитів:
WITH big_spenders AS (
SELECT user_id FROM orders WHERE total > 1000
)
SELECT name FROM users
WHERE id IN (SELECT user_id FROM big_spenders);Перевага CTE над глибоко вкладеними підзапитами росте разом зі складністю запиту — кілька CTE можна визначити послідовно, кожен спираючись на попередній, замість дедалі глибшої вкладеності дужок, яку важко читати й діагностувати.
WITH orders_per_user AS (
SELECT user_id, COUNT(*) AS orders_count
FROM orders
GROUP BY user_id
),
active_users AS (
SELECT user_id FROM orders_per_user WHERE orders_count >= 3
)
SELECT name FROM users WHERE id IN (SELECT user_id FROM active_users);Багато запитів можна написати і через JOIN, і через підзапит — планувальник PostgreSQL часто (хоч і не завжди) оптимізує обидва варіанти до однакового плану виконання. Практичне правило: JOIN природніший, коли потрібні стовпці з обох таблиць одночасно в результаті; підзапит/CTE — коли потрібна лише перевірка існування чи проміжне значення, а не самі дані пов'язаної таблиці.
Глибоко вкладені підзапити (підзапит усередині підзапиту всередині підзапиту) замість послідовних іменованих CTE — різко ускладнює читання й діагностику продуктивності.
Використання підзапиту там, де JOIN дав би той самий результат прозоріше й, часто, ефективніше — особливо коли з обох таблиць потрібні реальні дані, а не лише перевірка на існування.
Забувати, що результат підзапиту в IN (...) обчислюється для кожного порівнюваного значення (залежно від того, як планувальник вирішить виконати запит) — на великих обсягах даних варто перевіряти реальний план через EXPLAIN, а не покладатись на інтуїцію щодо продуктивності.
Підзапит — SELECT, вкладений усередину іншого запиту; CTE (WITH) — той самий механізм, оформлений як іменований, послідовно читабельний блок, особливо корисний для багатоступеневих запитів. JOIN зазвичай природніший, коли потрібні дані з обох таблиць одночасно; підзапит/CTE — коли достатньо перевірки існування чи проміжного обчисленого значення.