Модуль 18

PostgreSQL Data Types

Ось урок, створений спеціально для вас у стилі CS50: енергійний, зрозумілий та практичний.


🎓 CS50 Style: PostgreSQL Data Types

Або: Чому не можна зберігати суп у картонній коробці?

Привіт усім! 👋

Уявіть, що ви переїжджаєте в нову квартиру. У вас є купа речей: книги, одяг, посуд і... ну, скажімо, акваріум з рибками. Ви ж не будете складати акваріум у картонну коробку для книг? Чому? Тому що коробка розмокне, рибки (на жаль) постраждають, а ви отримаєте безлад.

База даних — це ваша вантажівка для переїзду. А типи даних — це спеціалізовані контейнери.

1. 🔥 Вступ: Проблема та мотивація

Давайте почнемо з реального життя. Уявіть, що ви будуєте банківський додаток. Ви створили таблицю і для балансу рахунку вибрали... ну, просто "текст". Ви пишете: Баланс: "100.50". Потім клієнт додає ще 50. База даних каже: "Окей, я додам текст до тексту". Результат: "100.5050".

Чекайте, що?! 😱 Замість 150.50 ми отримали нісенітницю.

Або ще гірше: ви зберігаєте дати як текст "01-02-2024". Як відсортувати їх? Комп'ютер почне сортувати за алфавітом, і "10-01-2023" раптом стане "більшим" за "02-01-2024".

Питання до вас: Чи хотіли б ви, щоб ваша зарплата розраховувалася з такою "текстовою" логікою? Впевнений, що ні.

Навіщо нам типи даних? 1. Цілісність (Integrity): Щоб у поле "Вік" ніхто випадково не записав слово "привіт". 2. Ефективність: Числу 42 потрібно всього 4 байти пам'яті. Тексту "сорок два" — значно більше. На мільярдах записів це гігабайти різниці. 3. Магія операцій: Якщо база знає, що це дата, вона дозволяє робити круті штуки, наприклад: дата + 7 днів.


2. 🧠 Теоретична база (Але без нудних лекцій)

PostgreSQL — це "Typed" (типізована) система. Це означає, що вона дуже сувора. Вона як педантичний бібліотекар: якщо книга стоїть не на тій полиці, вона не дозволить вам її туди поставити.

Давайте розглянемо "Велику Четвірку" типів, які покривають 90% ваших потреб.

А. Числа (Numbers)

Тут є пастка! ⚠️ * INTEGER (INT): Цілі числа (1, 50, -100). Використовуємо для кількості, ID, віку. * NUMERIC / DECIMAL: Числа з комою, де точність критична. Це для грошей! 💸 PostgreSQL зберігає їх точно, до копійки. * REAL / DOUBLE PRECISION: Числа з "плаваючою комою". Вони швидкі, але... трохи неточні. * Інтуїція: Це як відміряти борошно склянкою. Швидко, але не ідеально точно. Для наукових розрахунків — ок. Для грошей — НІКОЛИ.

Б. Текст (Text)

У старих базах даних (як старий MySQL) були дивні обмеження. У Postgres все простіше: * TEXT: Універсальний солдат. Може зберігати будь-яку довжину. Postgres оптимізує його "під капотом" ідеально. * VARCHAR(n): Текст з обмеженням до n символів. Використовуйте тільки якщо бізнес-логіка вимагає обмеження (наприклад, код країни з 2 літер).

В. Логіка (Boolean)

  • BOOLEAN: Тільки TRUE (так), FALSE (ні) або NULL (невідомо).
    • Приклад: is_active, has_paid. Це маленький перемикач світла. 💡

Г. Час (Date/Time)

  • DATE: Просто дата (2024-01-27). Календар на стіні.
  • TIMESTAMP: Дата + Час.
  • TIMESTAMPTZ (З запам'ятовуванням часового поясу): 🔥 Золотий стандарт.
    • Чому це важливо: Якщо ваш сервер у Києві, а клієнт у Нью-Йорку, TIMESTAMPTZ збереже момент часу в UTC, і кожен побачить свій правильний час. Без цього ви будете жити в пеклі часових поясів.

3. 🧪 Приклади (Coding Time!)

Давайте відкриємо термінал. Уявімо, ми робимо магазин кросівок.

Крок 1: Створюємо таблицю (Креслення)

CREATE TABLE sneakers (
    id SERIAL PRIMARY KEY,           -- SERIAL: авто-лічильник (1, 2, 3...)
    model_name TEXT NOT NULL,        -- Назва: текст будь-якої довжини
    size INT CHECK (size > 0),       -- Розмір: ціле число (і ми додали перевірку!)
    price NUMERIC(10, 2),            -- Ціна: 10 цифр всього, 2 після коми. Точність!
    is_in_stock BOOLEAN DEFAULT true,-- Чи є в наявності? За замовчуванням - так.
    created_at TIMESTAMPTZ DEFAULT NOW() -- Коли додали? Автоматично ставимо "зараз".
);

Що ви очікуєте, якщо ми виконаємо цей код? Postgres скаже CREATE TABLE. Він створив порожню "шафу" з підписаними полицями.

Крок 2: Додаємо дані (Happy Path)

INSERT INTO sneakers (model_name, size, price)
VALUES ('Air Jordan 1', 42, 199.99);

Все чудово. Postgres сам додав id (1), is_in_stock (true) і час створення.

Крок 3: Спроба зламати систему (Fail Path)

А тепер спробуємо запхати "суп у картонну коробку":

INSERT INTO sneakers (model_name, size, price)
VALUES ('Bad Data Shoes', 'forty-two', 'expensive');

Результат: ERROR: invalid input syntax for type integer: "forty-two"

💥 Бум! Postgres захистив нас від дурниць. Він не дозволив записати сміття в базу. Ось чому типи даних — це ваші охоронці.


4. 🛠 Практична частина

Тепер ваша черга! Відкрийте свій SQL-редактор (або уявіть його).

Завдання 1: "Мрійник" Створіть таблицю goals (цілі). Вона повинна мати: * Текст цілі. * Дату, до якої треба виконати (deadline). * Чи виконана вона (is_done). * Складність від 1 до 10 (використайте INTEGER).

Завдання 2: "Гроші на вітер" Спробуйте створити таблицю з полем wallet_balance типу REAL (плаваюча кома). Вставте туди 100.1 і 200.2. Зробіть SELECT, де ви додаєте ці числа. Спойлер: ви можете отримати щось типу 300.2999999999999. Поясніть собі, чому це погано для банку.

Завдання 3: "Виправ помилку" У вас є запит: INSERT INTO goals (deadline) VALUES ('tomorrow'); Це не спрацює. Чому? Як правильно записати завтрашню дату у форматі SQL (ISO 8601)?

Завдання 4: Міні-кейс Вам треба зберігати налаштування користувача (тема: темна/світла, сповіщення: вкл/викл, мова: ua). Створювати окрему колонку для кожного налаштування — це довго і нудно, бо налаштування часто змінюються. Підказка: Погугліть тип даних JSONB у PostgreSQL. Це суперсила Postgres. Спробуйте створити таблицю з полем settings JSONB.


5. 💡 Мислення як у розробника

Як думає Senior-розробник, коли проектує базу?

  1. "Який найгірший сценарій?"

    • Новачок думає: "Ціна — це просто число".
    • Профі думає: "Числа бувають неточні. Я візьму NUMERIC, щоб бухгалтер мене не вбив".
  2. "Чи буду я за цим шукати?"

    • Якщо ви зберігаєте дату як текст "2024/01", ви не зможете ефективно шукати "всі записи за січень". Використовуйте нативні типи (DATE, TIMESTAMP), бо вони індексуються і працюють блискавично.
  3. Порада на мільйон: Не бійтеся типу TEXT у Postgres. В інших базах кажуть "використовуй VARCHAR(255), щоб економити місце". У Postgres TEXT і VARCHAR працюють майже однаково швидко. Якщо не треба жорсткого ліміту — беріть TEXT і живіть спокійно.

  4. Час — це біль. Завжди, чуєте, ЗАВЖДИ використовуйте TIMESTAMPTZ (timestamp with time zone). Навіть якщо ваш проект лише для одного міста. Бізнес росте, сервери переїжджають. TIMESTAMPTZ — це ваша страховка.


6. 🧩 Підсумок

Отже, що ми маємо сьогодні?

  • База даних — це не смітник, це аптека. Все має бути на своїх місцях і підписане.
  • Типи даних визначають, що можна робити з інформацією (додавати, сортувати, обрізати).
  • Ви навчилися відрізняти INT від NUMERIC і знаєте, чому TIMESTAMPTZ — ваш найкращий друг.
  • Ви тепер вмієте створювати "креслення" для надійних таблиць.

Тепер ви вмієте: Проектувати надійний фундамент для даних, який не розвалиться під навантаженням.

🚀 Тизер: Але стривайте! Ми навчилися зберігати дані. А що, якщо у нас мільйон кросівок, і нам треба знайти всі червоні 42-го розміру за 0.01 секунди? Простого SELECT буде замало... На наступному уроці ми поговоримо про Індекси (Indexes) — як перетворити вашу базу даних з повільної черепахи на ракету.

Це був CS50. (Тобто, наш урок). Побачимось! 🎬