Читабельний SQL, аналіз датасету та корисні поради з власного досвіду

Всім привіт! Мене звати Юрій, і я працюю дата-аналітиком. У цій статті хочу поділитися своїм досвідом та корисними порадами, які допомагають мені у щоденній роботі з SQL.

Спочатку розглянемо, як зробити SQL-код читабельним та зрозумілим — ці принципи я перейняв від свого керівника і тепер використовую щодня.

Далі розповім про свій підхід до первинного аналізу датасетів — це важливий крок, який допомагає швидко отримати загальне уявлення про дані.

І на завершення поділюся кількома корисними порадами з власного досвіду.

Форматування коду

Читабельний код не лише полегшує розуміння, а й прискорює процес налагодження та внесення змін.

Розглянемо просту задачу, щоб підкреслити важливість структурованого коду:

Потрібно отримати список клієнтів із певними критеріями та перевірити, чи мають вони VIP-карту. Якщо так, то вивести сумарний баланс їхніх карт, інакше — 0.

Приклад коду до форматування:

Після структурування:

Розглянемо основні зміни та пояснимо їхню важливість.

Основні принципи читабельності

1. Коми на початку колонок. Цей підхід спочатку може здаватися незвичним, але з часом стає зручним і логічним. Суть у тому, що кожна нова колонка в запиті починається з нового рядка, а кома стоїть на початку (окрім першої колонки). Всі колонки вирівняні по одній вертикальній лінії, що робить код структурованим і легким для читання.

2. Використання аліасів, префіксів та коментарів:

  • Аліаси для таблиць і колонок роблять код більш зрозумілим, особливо у складних запитах. Важливо, щоб аліаси колонок були вирівняні по одній лінії — це спрощує сприйняття запиту та робить його більш структурованим.

3. Оформлення CTE

CTE слід відокремлювати порожніми рядками зверху і знизу, а весь код усередині повинен мати відступ за допомогою одного tab або кількох пробілів.

Переважно використовуйте CTE замість вкладених запитів, оскільки це робить код структурованішим і значно покращує його читабельність.

4. Форматування коду в WHERE and HAVING:

Перша умова повинна записуватися в тому ж рядку, що й ключове слово. Кожна наступна умова має починатися з нового рядка та вирівнюватися по вертикалі з ключовим словом.

Такий підхід значно покращує читабельність коду та спрощує його розуміння.

5. The Large CASE Statement. Часто доводиться писати великі умови в case. Ось приклад:

Раджу вирівнювати код для кращого сприйняття. Найзручніше розташовувати then на одній лінії, так само як і аліаси — це дозволяє одразу побачити результати умов.

Також вирівнюю повторювані умови, щоб їх було легше читати.

Іноді додаю горизонтальні лінії між блоками when, щоб візуально розділити логічні частини. На мою думку, це також покращує читабельність коду.

6. Lowercase formatting

Раніше я писав ключові слова у верхньому регістрі, але зараз використовую лише нижній. Це вже питання звички, але бачу в цьому таку перевагу:

  • Увесь код виглядає однорідним, що полегшує його сприйняття.
  • До того ж IDE й без того підсвічує ключові слова, тому немає потреби виділяти їх великими літерами.

Дотримуючись цих простих правил, ви зробите код більш структурованим і зрозумілим, що дозволить іншим аналітикам швидше розібратися у вашому запиті.

Мій підхід до аналізу датасету

Хочу поділитися тим, як я зазвичай отримую перше базове уявлення про датасет. Це допомагає швидко зрозуміти структуру даних, знайти потенційні проблеми та підготувати їх для подальшого аналізу.

1. Перший крок — переглянути список колонок та їхні типи даних.

2. Далі для категоріальних колонок мені дуже подобається використовувати такий запит:

Він дозволяє одразу побачити всі унікальні значення, їхню кількість, а також визначити, які дані зустрічаються найчастіше, а які — рідше.

Також швидко можна проаналізувати датасет в Python з допомогою бібліотеки pandas.

Кілька корисних вбудованих функцій:

  • info() — виводить загальну інформацію про DataFrame, включно з кількістю значень, типами даних і використанням пам’яті.
  • describe() — обчислює основні статистичні характеристики числових стовпців, такі як середнє, медіана, мінімум, максимум і квартилі.
  • isna().sum() — підраховує кількість пропущених значень у кожному стовпці.
  • duplicated.sum() — підраховує кількість дубльованих рядків.

Ці методи допомагають швидко отримати загальне уявлення про структуру даних і виявити потенційні проблеми.

3. Тепер з розумінням датасету можна братися до розв’язання задачі. Часто важко одразу зрозуміти, як дійти до фінального результату. Тому потрібно:

  • Розбити задачу на прості кроки.
  • Виконати перший крок, потім другий.
  • З’єднати їх і поступово рухатися до розв’язку.

4. Після першого розв’язання у вас можуть з’явитися ідеї про те, як зробити її простіше. Тому наступним кроком може бути оптимізація, якщо це необхідно.

5. Завершальний етап — форматування коду, про яке йшлося раніше.

Корисний SQL-трюк: where true

Один із моїх улюблених прийомів під час аналізу даних — використання where true (або його аналог where 1 = 1).

Навіщо це потрібно?

Коли необхідно протестувати кілька різних умов у where, завжди дратує, якщо доводиться коментувати першу умову, адже це змушує переставляти або виправляти інші.

І тут у пригоді стає where true — дозволяє цього уникнути та швидко експериментувати з фільтрами.

NULL Values

Припустимо, що є таблиця client_balances, яка містить ID клієнта, його баланс картки та депозиту. Потрібно порахувати сумарний баланс картки та депозиту і вибрати клієнтів із балансом понад 4000.

Якщо просто підсумувати значення, отримаємо такий результат:

Спочатку може здатися, що результатом повинні бути клієнти з id = 2 та id = 3.

АЛЕ через те, що клієнт з id = 3 має null-значення в колонці deposit_balance, при додаванні буде не 5000, а null.

Будь-яка операція з null повертає null, оскільки це означає відсутність значення.

Тому розв’язанням цієї проблеми є додавання таких функцій, як coalesce(deposit_balance, 0) або ifNull(deposit_balance, 0).

Вирішив поділитись цим, оскільки часто стикався з подібною проблемою.

Усвідомлення важливості бізнес-логіки

Також хочу розповісти про скіл, який, на мою думку, є ключовим для дата-аналітика.

На початку кар’єри в компанії, де я зараз працюю, я виконував завдання суто за технічними вказівками, не розуміючи їхнього бізнес-контексту. Через це мої рішення були технічно правильними, але могли не відповідати реальним потребам бізнесу. У підсумку деякі задачі просто не приносили користі, ніби робота була помножена на нуль.

Я усвідомив, що без розуміння бізнес-логіки неможливо створювати реальну цінність. Тому почав:

  • Задавати більше уточнюючих запитань замовникам, щоб краще розуміти їхні реальні потреби та кінцеву мету задачі, адже те, що вони хочуть, часто відрізняється від того, що їм насправді треба.
  • Ставати більш допитливим і перевіряти свої рішення з різних площин — не тільки технічно, а й з бізнесової точки зору.

Завдяки цьому я почав працювати осмисленіше, і це повністю змінило мій підхід до роботи.

Саме розуміння важливості софт-скілів допомогло мені уникати зайвої роботи, зосереджуватися на ключових проблемах та знаходити оптимальні рішення, які приносять реальну цінність бізнесу.

Корисні YouTube-канали

На завершення хочу поділитися корисними YouTube-каналами, які значно допомогли мені розібратись в аналітиці:

  • Roman Povzyk — поради та тестові співбесіди, які додали мені впевненості при їх проходженні.
  • Nikita Tymoshenko — структуровані та повні курси.
  • Alex The Analyst — тут зібрана вся корисна інформація по дата-аналітиці.

На цих каналах можна знайти багато корисного контенту, який допоможе розширити знання та покращити навички в аналітиці даних.

Висновок

Читабельний код значно спрощує розуміння, підтримку та внесення змін. Дотримуючись простих правил форматування, можна зробити SQL-запити структурованими та легшими для сприйняття.

Аналіз датасету — це перший і важливий крок у роботі з даними. Використовуючи SQL та Python, можна швидко отримати загальне уявлення про структуру даних, виявити аномалії та підготувати основу для подальшого аналізу.

Але технічні навички — це лише частина роботи аналітика. Розуміння бізнес-логіки є не менш важливим фактором, який визначає ефективність прийнятих рішень. Аналітик, який розуміє реальні потреби бізнесу, не лише створює правильні запити, а й генерує реальну цінність. Вміння ставити правильні запитання, уточнювати кінцеві цілі аналізу та перевіряти свої рішення з різних точок зору дозволяє уникати зайвої роботи та зосереджуватися на ключових аспектах.

Крім того, варто звертати увагу на особливості роботи з null, щоб уникнути несподіваних результатів у розрахунках. Використання таких функцій як coalesce або ifNull допомагає обійти цю проблему та отримати коректні результати.

Знання подібних технік і трюків значно покращує ефективність роботи з SQL і аналітикою в цілому.

Які підходи ви використовуєте для аналізу датасетів?
Якими лайфхаками користуєтеся у своїй роботі з даними?

Буду радий дізнатися про ваш досвід!

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

👍ПодобаєтьсяСподобалось22
До обраногоВ обраному10
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Гарна стаття, дякую!
Звісно, багато нюансів, про які описують в коментах, мають підгрунтя, але потрібно не забувати, що все залежить ще і від складності вимог та циклу життя даних запитів.

Пара зауважень, що кинулось в очі

1. Коми на початку колонок. Цей підхід спочатку може здаватися незвичним, але з часом стає зручним і логічним.

Цілком може бути, але це — питання смаку.
Основна потреба цих ком — це можливість легко закоментувати-розкоментувати поля у select-і без того, щоби гратись із комами.
Але, коли коми спочатку — закоментовування першого поля заставляє гратись із комами.
Коли коми у кінці — закоментовування останнього поля заставляє гратись із комами.

Використання впорядкованих числових префіксів (t1, t2, t3...) робить код більш читабельним

Повністю не згоден — коли у тебе десяток таблиць, і декілька self-join-ів, то ці числові префікси стають ні до чого. Аліаси мають бути скороченням від того, чим є таблиця у запиті — зазвичай, таблиця представляє саму себе, але є випадки, коли це не так.

Переважно використовуйте CTE замість вкладених запитів, оскільки це робить код структурованішим і значно покращує його читабельність.

І обов’язково перевірити всі плани запитів, щоби не було потім боляче.
Також, розглянути заміну на lateral join, якщо підтримує СКБД (apply/cross apply для mssql), або і взагалі матеріалізовані дані.

group by 1

Краще писати назву колонки.
Не всі СКБД підтримуть номери колонок у group by, тому краще зразу заставляти себе писати так, як підтримується всюди — потім легше жити буде.

Дякую за те що поділилися досвідом, є цікаві поради.

Не зрозуміло правда чому в статтю про SQL підмішався pandas, але менше з тим.

Підкажіть будь-ласка а то Ви ручками 🤲 форматуєте чи якийсь інструмент використовуєте? Той же sqlfluff до прикладу sqlfluff.com

По trailing comma — як на мене тут головне що потім при додаванні нових умов/колонок в репозиторії підсвічує різницю тільки новий рядок , без коми в попередньому .

В вашому прикладі у вас зʼявляється аліас vip_cards на СТЕ, потім в основному запиті зʼявляється новий нумерований аліас t1 . Тобто на кожну порцію даних вже треба тримати 2 назви в голові- то не є добре. Особливо якщо таких СТЕ/джойнів з десяток .

Імхо, наївне припущення що ВІП картки завжди будуть закодовані як код=3 , то закладати підґрунтя майбутніх помилок. Якщо є якийсь атрибут яким бізнес однозначно визначає ВІП картки — він має бути відображений в коді через підзапит або окрему самописну функцію/макро, а не харч код.

Group by 1,2,3 на мою думку виправдано коли йде блоком з order by типу
Select year(), month(), avg(sales_amount)
From ....
Group by 1,2
Order by 1,2
Ще є така думка стосовно цього www.getdbt.com/...​l-a-defense-of-group-by-1

А от довжелезні Case/When/Then це прям фу-фу-фу. Ніде такого не бачив 👀. Максимально розносьте складові коду по вертикалі- легше скролити, легше порівнювати. Не дарма в тому самому Python (ну раз вже pandas виліз) є РЕР на довжину рядка в 80 символів .

Раджу звернути увагу на Joe Celko’s sql programming style — багато речей пояснюються більш ґрунтовно , там же і про rivering і про sensible aliases

Дякую за поради! Так ручками форматую. Подивлюсь про sqlfluff і Joe Celko’s

Так ручками форматую.

Meh.
Если в компании есть какие-то гайдлайны по форматированию, то их и придерживаются, и они могут быть зашиты в «общие» инструменты для форматирования, типа бьютифаера в IDE.
Тогда ваш текст в принципе не имеет смысла, т.к. форматируете не так, как вам нравится, а так, как принято.
Если же гайдлайнов нет, то проще и дешевле самому написать себе набор правил для бьютифаера — а не каждый раз насиловать tab-кнопку.

От я коли заголовок побачив — сподівався що тут якийсь розбір налаштувань і сетапу для якогось ІДЕ та лінтера. Може приклад як це ще в CI/CD зашити.

У Вас до речі нема прикладів які інструменти Ви використовуєте для форматування?

У нас (в компании) нет какого-то гайдлайна по форматированию (к сожалению), поэтому каждый извращается как умеет.
Конкретно у меня — встроенный в PL/SQL Developer бьютифаер, который форматирует выделенный код согласно настроенным правилам (в rule-файле) — он достаточно базовый по настройкам, но в целом ОК.
В Oracle SQL Developer тоже есть аналогичный функционал, SQL Formatter (www.databasestar.com/...​sql-developer-format-sql здесь описание, например).

В целом, надо смотреть конкретную IDE, с которой вы работаете — почти во всех адекватных (сложнее notepad’а) будет какой-нибудь аналог.
По CI/CD не подскажу, но наверняка есть готовые решения.
Мне когда-то понравился pre-commit (github.com/...​e-commit/pre-commit-hooks), но опять же — там может не быть готового плагина для PLSQL (надо писать), да и внедрять такое счастье надо на уровне компании / проекта.

А взагалі які інструменти на проекті є? Де свої запити пишете — DBeaver, pgAdmin, Snowflake/Trino UI?

Чи зберігаєте десь в репозиторіі їх потім? Якщо запит штибу створити нову табличку або додати колонку у вже існуючу — як ці зміни в прод потрапляють?

GROUP BY 1 наверное, лучше тоже заменить на имя столбца

Meh.

Аліаси для таблиць і колонок роблять код більш зрозумілим

Да, но не только. В первую очередь они нужны, чтобы при добавлении поля в таблицу, у вас запросы не свалились с column ambiguously defined.
В вашем же примере в select’е алиасы есть, в предикатах — нет.

Використання впорядкованих числових префіксів (t1, t2, t3...) робить код більш читабельним, оскільки усуває необхідність придумувати аліаси вручну та забезпечує логічну структуру

Полностью наоборот. Алиас должен указывать на логический источник данных (таблица, вьюха, подзапрос), а не на порядок размещения таблиц в запросе (который вообще может быть любым). Условно, для таблицы customers приемлемыми алиасами были бы «c» для простых запросов на пару таблиц, «cust» или «customers» для более сложных.

Переважно використовуйте CTE замість вкладених запитів

...помня при этом об эффектах, которые это оказывает на производительность.

Будь-яка операція з null повертає null, оскільки це означає відсутність значення.

Кажется, это есть буквально в КАЖДОМ учебнике по SQL — и нет, всё равно это тащат регулярно в «полезные статьи» :)

Кажется, это есть буквально в КАЖДОМ учебнике по SQL — и нет, всё равно это тащат регулярно в «полезные статьи» :)

Потому что при любом уровне опыта можешь на него нарваться. Колонку сделали nullable, тебя не предупредили, у тебя какое-нибудь not (x=1 or x=2), и привет. Вот такая это тупая мина в языке. Надо напоминать ежедневно и еженощно.

Полностью наоборот.

Точно, какая-то рубрика «вредные советы». Как только запрос станет достаточно большим, в этих t1, t2 просто утонешь

якщо запит стане великим, аналітик віддасть задачу розробнику, може навіть архітектору і тричі сіньойору )))

панове, враховуйте що ви «наїхали» на аналітика, а не девелопера ))) у аналітиків зовсім інщі задачі при створені запитів, ніж у девелоперів.

завжди користувався аліасами на пару символів, бо писати більше — довго, зайві кнопки на клавіатурі, а структуру запиат ти і так пам’ятаешь, 80% запитів — одноразові, виконав — забув.
«пару разів» писав щось типу «оптимизації запитів для інтеграції» с кейсами та мільйоном джойнів... але то таке, теж одноразове і залежить від обставин. Булаб можливість повисів би задачу на розробника.

аліаси на пару символів не зобов’язані бути t1, t2.
бо в процесі покращення запиту замінили зв’язок через третю таблицю на прямий зв’язок — от у вас t2 вже пощез. А потім додали left join десь поближче до from — от у вас аліаси вже t1, t5, t3, t4
оочінь інтірєсно потім згадувати де хто.

Підписатись на коментарі