Фото: Tim Gouw на Unsplash
Як фахівці з даних, ми розуміємо, що розповідання історій — це наша найпотужніша навичка. Ми ретельно готуємо наші презентації, вибираємо впливові візуалізації і постійно думаємо про те, як довго увага нашої аудиторії може зберігатися. Але коли мова йде про написання коду, ми часто забуваємо ці самі принципи.
У сучасному робочому середовищі перегляд коду (code review) є основною частиною нашого робочого процесу. Незалежно від того, чи переглядаєте ви запит колеги, чи ваш код переглядають, читабельність не є чимось необов'язковим — це необхідність. Тож чому б не застосувати ці самі принципи розповідання історій до написання SQL?
Давайте поговоримо про підзапити (subqueries) і чому я вважаю їх ворогом читаємого коду. Люди природно читають зліва направо, але підзапити змушують наші мізки виконувати складні логічні вправи. Розглянемо цей приклад:
SELECT
customer_name,
order_count,
avg_order_value
FROM customers c
WHERE customer_id IN (
SELECT
customer_id
FROM orders
WHERE total_amount > (
SELECT
AVG(total_amount)
FROM orders
)
GROUP BY customer_id
HAVING COUNT(*) > 5
);
Щоб зрозуміти цей запит, вам, можливо, доведеться:
- Почати читати з зовнішнього SELECT
- Перейти до найглибшого підзапиту, щоб зрозуміти, як обчислюється середнє значення
- Повернутися на один рівень, щоб побачити, як це середнє значення використовується
- І, зрештою, повернутися до початку, щоб зрозуміти, які дані ми насправді отримуємо
Це схоже на читання книги, де вам потрібно перевертати на останню сторінку, щоб зрозуміти перший розділ. Натомість ось та сама логіка, але з використанням загальних таблиць (Common Table Expressions, CTE):
WITH avg_order AS (
SELECT AVG(total_amount) as avg_amount
FROM orders
),
frequent_high_value_customers AS (
SELECT
customer_id,
COUNT(*) as order_count
FROM orders
WHERE total_amount > (SELECT avg_amount FROM avg_order)
GROUP BY customer_id
HAVING COUNT(*) > 5
)
SELECT
c.customer_name,
fhc.order_count,
AVG(o.total_amount) as avg_order_value
FROM frequent_high_value_customers fhc
JOIN customers c ON c.customer_id = fhc.customer_id
JOIN orders o ON o.customer_id = c.customer_id;
Варіант з CTE розповідає набагато зрозумілішу історію:
- Спочатку ми обчислюємо середню суму замовлення
- Потім ідентифікуємо клієнтів, які часто роблять замовлення вище середнього
- І, зрештою, отримуємо деталі цих клієнтів та їхні патерни замовлень
CTE — це не лише про читаємість. Вони модульні. Ви можете легко тестувати кожен CTE окремо, запустивши його самостійно, що значно спрощує налагодження та валідацію. Вони також полегшують підтримку коду, оскільки ви можете змінювати одну частину без необхідності розплутувати вкладену логіку.
Отже, наступного разу, коли вас захопить бажання написати підзапит, пам’ятайте: ваш код не лише для комп’ютерів — він також для людей. Вибирайте ясність замість складності, і ваше майбутнє "я" (та колеги) будуть вдячні.
Перекладено з: I hate SQL subqueries. Here’s why