Ось готовий урок, створений за твоїм майстер-промптом. Я намагався передати енергію, структуру та стиль подачі Девіда Малана, адаптувавши це для української аудиторії.
🎓 CS50: Вартові твоїх даних (Constraints & Data Integrity)
Привіт, друзі! Це CS50, і сьогодні ми поговоримо про те, що відрізняє професійну базу даних від звичайного текстового файлу, в якому панує хаос.
Сьогоднішня тема — Constraints (Обмеження) та Data Integrity (Цілісність даних).
1. 🔥 Вступ: Чому не можна довіряти нікому?
Уявіть, що ви відкриваєте новий банк. Ви наймаєте касира, назвемо його, скажімо, Джон. І ось приходить перший клієнт, щоб відкрити рахунок. Джон бере анкету і... забуває записати ім'я клієнта. Або в полі "Баланс" пише: "-1000 доларів" (бо клієнт йому не сподобався). Або ще гірше — видає двом різним людям абсолютно однаковий номер рахунку.
Запитання до вас: Що станеться з вашим банком через тиждень? (Пауза для роздумів) Правильно. Хаос. Судові позови. Банкрутство.
У світі баз даних ми називаємо це "Garbage In, Garbage Out" (Сміття на вході — сміття на виході).
Якщо ви дозволите своїй програмі записувати в базу будь-що, вона це зробить. Вона запише користувача без email-у, товар з від'ємною ціною або замовлення для клієнта, якого не існує.
Навіщо нам Constraints (Обмеження)? Щоб перетворити базу даних з "смітника" на фортецю. База даних має бути останнім рубежем оборони. Навіть якщо ваш фронтенд зламався, навіть якщо бекенд-розробник (можливо, це ви о 3-й ночі) припустився помилки — база даних має сказати: "Стоп! Я це не збережу, бо це порушує закони логіки".
2. 🧠 Теоретична база: Як це працює «під капотом»
Давайте розберемося з інструментами, які у нас є. Уявіть, що ви — фейс-контроль у нічному клубі (вашій таблиці). У вас є чіткі інструкції, кого пускати, а кого — ні.
Ось ваші головні правила (Constraints):
1. NOT NULL (Не порожнє)
Це просто. Чи може існувати користувач без імені? Ні. * Логіка: Це поле обов'язкове для заповнення. * Аналогія: Ви не можете отримати посилку, якщо не вкажете адресу доставки.
2. UNIQUE (Унікальність)
Чи можуть два користувачі мати однаковий email? Ні, бо як ми їх розрізнимо під час входу? * Логіка: Значення в цьому стовпчику не можуть повторюватися.
3. PRIMARY KEY (Первинний ключ)
Це Святий Грааль вашої таблиці. Це унікальний ідентифікатор кожного рядка (зазвичай id).
* Як це працює: Це комбінація NOT NULL + UNIQUE. У кожного рядка має бути паспорт, і він має бути унікальним.
* Запам'ятати: У кожної таблиці має бути Primary Key. Крапка.
4. CHECK (Перевірка умов)
Тут ми вмикаємо логіку. * Приклад: Ціна товару > 0. Вік користувача >= 18. * Логіка: Це "іфчик" (if statement), який живе прямо в базі даних.
5. FOREIGN KEY (Зовнішній ключ) — Найважливіше!
Це міст між таблицями.
Уявіть таблицю Orders (Замовлення) і Users (Користувачі). Замовлення має знати, хто його зробив. Ми записуємо user_id у таблицю замовлень.
* Що робить Foreign Key: Він гарантує, що ви не зможете створити замовлення для користувача з id=999, якщо такого користувача не існує в таблиці Users. Він також не дасть видалити користувача, якщо у нього є активні замовлення (щоб замовлення не стали "сиротами").
* Термін: Це називається Referential Integrity (Посилальна цілісність).
3. 🧪 Приклади (від хаосу до порядку)
Ми будемо використовувати SQL (PostgreSQL/MySQL стиль), але логіка однакова всюди.
Сценарій 1: Хаос (Без обмежень)
Створимо таблицю для інтернет-магазину.
CREATE TABLE products (
id INT,
name VARCHAR(100),
price DECIMAL,
sku VARCHAR(50) -- артикул товару
);
Що тут не так? Давайте спробуємо зламати систему:
INSERT INTO products (id, name, price, sku) VALUES (1, NULL, -50, 'ABC-123');
INSERT INTO products (id, name, price, sku) VALUES (1, 'iPhone', 1000, 'ABC-123');
Результат: База це "з’їла".
1. У нас два товари з id=1. Як ми їх оновимо?
2. У першого товару немає назви (NULL).
3. Перший товар коштує -50. Ми будемо доплачувати покупцю?
4. Артикул ABC-123 дублюється.
Це катастрофа.
Сценарій 2: Порядок (Додаємо Constraints)
Давайте перепишемо це як професіонали.
Чого ми очікуємо? Ми хочемо, щоб база даних видавала помилку, якщо ми спробуємо вставити нісенітницю.
CREATE TABLE products (
id INT PRIMARY KEY, -- Унікальний, не null
name VARCHAR(100) NOT NULL, -- Обов'язкове ім'я
price DECIMAL CHECK (price > 0), -- Тільки позитивна ціна
sku VARCHAR(50) UNIQUE -- Унікальний артикул
);
Тепер спробуємо ті ж самі вставки.
INSERT INTO products ... VALUES (1, NULL, ...)-> ❌ Error: Column 'name' cannot be null.INSERT INTO products ... VALUES (..., -50, ...)-> ❌ Error: Check constraint failed.- Вставимо нормальний товар:
INSERT INTO products VALUES (1, 'iPhone', 1000, 'ABC-123');-> ✅ Success! - Спробуємо вставити інший товар з таким самим SKU:
INSERT INTO products VALUES (2, 'Samsung', 900, 'ABC-123');-> ❌ Error: Duplicate entry for key 'sku'.
Бачите? База даних захищає вас від ваших же помилок!
4. 🛠 Практична частина
Час "забруднити руки". Якщо у вас є доступ до SQL-терміналу або онлайн-редактора (наприклад, SQLFiddle), спробуйте це зараз.
Завдання 1: Створіть таблицю users
* Поля: id (primary key), username (текст), age (число).
* Умови: Ім'я має бути унікальним і не порожнім. Вік має бути 18 або більше.
Завдання 2: Тест на міцність * Спробуйте додати користувача без імені. * Спробуйте додати 17-річного. * Що вам відповіла база даних?
Завдання 3: Робота з Foreign Key (Зірочка ⭐)
У вас є таблиця users. Створіть таблицю posts (дописи блогу).
* У таблиці posts має бути поле user_id.
* Зробіть це поле Foreign Key, яке посилається на users(id).
* Питання: Що станеться, якщо ви спробуєте додати пост для user_id = 999, якого немає в таблиці users?
Завдання 4: Міні-кейс "Служба таксі"
Придумайте структуру таблиці rides (поїздки).
Які обмеження ви б додали до полів:
* status (може бути лише: 'started', 'completed', 'cancelled')?
* driver_rating (від 1 до 5)?
5. 💡 Мислення як у розробника
Ви можете запитати: "Девід, навіщо мені це прописувати в базі? Я ж можу перевірити це в коді на Python/JavaScript перед збереженням!"
Це типова помилка новачків. Ось як думає досвідчений архітектор (Senior Developer):
- Принцип "Глибинного захисту" (Defense in Depth): Ваш JavaScript код на фронтенді можуть обійти хакери. Ваш Python код на бекенді може мати баг. Але база даних — це фундамент. Якщо дані зіпсуються там, виправити це буде майже неможливо.
- Дані живуть довше за код: Сьогодні ваш сайт на PHP, завтра ви переписуєте його на Node.js, післязавтра — мобільний додаток на Swift. Всі вони працюють з однією базою. Якщо правила (Constraints) "вшиті" в базу, вам не треба дублювати логіку перевірки в кожному новому додатку.
- Порада з практики:
Завжди давайте імена своїм обмеженням (constraints).
Замість просто
CHECK (price > 0), пишітьCONSTRAINT check_price_positive CHECK (price > 0). Коли через рік ви отримаєте помилку, повідомлення "Error: check_price_positive failed" скаже вам набагато більше, ніж просто "Error: constraint failed".
6. 🧩 Підсумок
Отже, що ми сьогодні поклали до свого багажу знань:
- Дані мають бути цілісними. Без цього ваш додаток — картковий будинок.
- Constraints — це ваші найкращі друзі.
NOT NULL,UNIQUE,PRIMARY KEY,FOREIGN KEY,CHECK. - Foreign Key тримає зв'язок між таблицями і не дозволяє з'являтися даним-"сиротам".
Що ви тепер вмієте? Ви вмієте проектувати таблиці, які неможливо зламати "сміттєвими" даними. Ви будуєте надійний фундамент.
Що далі? Тепер, коли наші дані надійно захищені і структуровані, виникає нове питання: "А що, якщо у нас мільйон користувачів? Як знайти потрібного за 0.01 секунди, а не гортати всю книгу?" На наступному уроці ми поговоримо про магію швидкості — Індекси (Indexes).
Це був CS50. Побачимось!