Як думати на SQL
Автор: Рахім Давлеткалієв
Якщо ви схожі на мене, то погодьтеся: SQL - це одна з тих штук, які на перший погляд здаються легкими (читається ніби по-англійськи!), але чомусь доводиться гуглити кожен простий запит, щоб знайти правильний синтаксис.
А потім починаються джойни, агрегування, підзапити і виходить зовсім біліберда. Начебто такий:
Буе! Таке злякає будь-якого новачка або навіть розробника середнього рівня, якщо він бачить SQL вперше. Але не все так погано.
Інтуїтивно зрозуміло, і за допомогою цього посібника я сподіваюся знизити поріг входу в SQL для новачків, а вже досвідченим запропонувати по-новому поглянути на SQL.
Не дивлячись на те, що синтаксис SQL майже не відрізняється в різних базах даних, у статті для запитів використовується PostgreSQL. Деякі приклади працюватимуть у MySQL та інших базах.
1. Три чарівні слова
У SQL багато ключових слів, але SELECT , FROM і WHERE є практично у кожному запиті. Трохи пізніше ви зрозумієте, що ці три слова є найбільш фундаментальними аспектами побудови запитів до бази, а інші, складніші запити, є лише надбудовами над ними.
2. Наша база
Давайте поглянемо на базу даних, яку ми будемо використовувати як приклад у цій статті:
У нас є книжкова бібліотека та люди. Також є спеціальна таблиця для обліку виданих книг.
3. Простий запит
Запит буде таким:
А результат таким:
| 2 | The Lost Symbol |
| 4 | Inferno |
Досить просто. Давайте розберемо запит, щоб зрозуміти, що відбувається.
3.1 FROM - звідки беремодані
Зараз це може здатися очевидним, але FROM буде дуже важливим пізніше, коли ми перейдемо до з'єднань та підзапитів.
FROM вказує на таблицю, за якою потрібно робити запит. Це може бути вже існуюча таблиця (як у прикладі вище) або таблиця, створювана на льоту через з'єднання або підзапити.
3.2 WHERE - які дані показуємо
WHERE просто поводиться як фільтррядок, які ми хочемо вивести. У нашому випадку ми хочемо бачити лише ті рядки, де значення в колонці author - це Dan Brown.
3.3 SELECT - як показуємо дані
Тепер, коли у нас є всі потрібні колонки з потрібної нам таблиці, потрібно вирішити, як саме показувати ці дані. У нашому випадку потрібні лише назви та ідентифікатори книг, тому саме це ми і виберемо за допомогою SELECT . Заодно можна перейменувати колонку використовуючи AS.
Весь запит можна візуалізувати за допомогою простої діаграми:

4. З'єднання (джойни)
Тепер ми хочемо побачити назви (не обов'язково унікальні) всіх книг Дена Брауна, які були взяті з бібліотеки, і коли ці книги треба повернути:
| The Lost Symbol | 2016-03-23 00:00:00 |
| Inferno | 2016-04-13 00:00:00 |
| The Lost Symbol | 2016-04-19 00:00:00 |
Здебільшого запит схожий на попередній крім секції FROM . Це означає, що ми запитуємо дані з іншої таблиці. Ми не звертаємось ні до таблиці “books”, ні до таблиці “borrowings”. Натомість ми звертаємося до нової таблиці, яка створилася з'єднанням цих двох таблиць.
borrowings JOIN books ON borrowings.book > — це, вважай, нова таблиця, яка була сформованакомбінуванням всіх записів з таблиць "books" і "borrowings", в яких значення bookid збігаються. Результатом такого злиття буде:
А потім ми запитуємо до цієї таблиці так само, як у прикладі вище. Це означає, що при з'єднанні таблиць потрібно дбати лише про те, як провести це з'єднання. А потім запит стає таким самим зрозумілим, як у випадку із «простим запитом» з пункту 3.
Спробуємо трохи складніше з'єднання з двома таблицями.
На цей раз давайте підемо знизу вгору:
Крок Step 1 - звідки беремо дані? Щоб отримати потрібний нам результат, потрібно з'єднати таблиці “member” та “books” із таблицею “borrowings”. Секція JOIN виглядатиме так:
Результат з'єднання можна побачити за посиланням.
Крок 3 - як показуємо дані? Тепер, коли дані отримані, потрібно просто вивести ім'я та прізвище тих, хто взяв книги:
Супер! Залишилося лише об'єднати три складові і зробити потрібний нам запит:
| Міке | Willis |
| Ellen | Horton |
| Ellen | Horton |
Чудово! Але імена повторюються (вони унікальні). Ми скоро це виправимо.
5. Агрегування
Грубо кажучи, агрегування потрібні для конвертації кількох рядків на одну. При цьому під час агрегування для різних колонок використовується різна логіка.
Давайте продовжимо наш приклад, в якому з'являються імена, що повторюються. Видно, що Ellen Horton взяла більше однієї книги, але це не найкращий спосіб показати цю інформацію. Можна зробити інший запит:
Що дасть нам потрібний результат:
| Міке | Willis | 1 |
| Ellen | Horton | 2 |
Майже всі агрегації йдуть разом із виразом GROUP BY. Ця штука перетворює таблицю, яку можна було б отримати запитом у групи таблиць. Кожна група відповідає унікальному значенню (або групі значень) стовпчика, який ми вказали в GROUP BY . У нашому прикладі ми конвертуємо результат із минулого вправи до групи рядків. Ми також проводимо агрегування з count, яка конвертує кілька рядків у ціле значення (у нашому випадку це кількість рядків). Потім це значення приписується кожній групі.
Кожен рядок в результаті є результатом агрегування кожної групи.
Можна дійти логічного висновку, що всі поля в результаті повинні бути або вказані в GROUP BY , або за ними має здійснюватись агрегування. Тому що всі інші поля можуть відрізнятись один від одного в різних рядках, і якщо вибирати їх SELECT 'ом, то незрозуміло, які з можливих значень потрібно брати.