Реляційна модель даних
Реляційна модель даних
Вступ: Чому математика?
У попередньому уроці ми дізналися, що Едгар Кодд у 1970 році запропонував революційну ідею - використовувати прості таблиці замість складних ієрархічних та мережевих структур. Але що робить реляційну модель по-справжньому потужною?
Відповідь: Математична строгість!
- Поведінка системи передбачувана
- Можна формально доводити правильність операцій
- Оптимізація запитів має математичне обґрунтування
- Є чіткі правила для роботи з даними
Від життя до математики
Розглянемо звичайну життєву ситуацію:
Приклад: У бібліотеці є картотека з книгами. Кожна картка містить:
- Назву книги
- Автора
- Рік видання
- ISBN
Питання: Як це описати математично?
Еволюція понять:
- Реальний світ - картотека з картками
- Математика - відношення (relation)
- Практика - таблиця (table)
Математичні основи
Теорія множин: базові поняття
Приклади множин:
КРАЇНИ = {Україна, Польща, Німеччина, Франція}
ПАРНІ = {2, 4, 6, 8, 10, ...}
АВТОРИ = {Шевченко, Франко, Леся Українка}
Важливі властивості множин:
Кожен елемент може бути в множині тільки один раз.
{1, 2, 3, 2, 1} = {1, 2, 3}
Дублікати автоматично видаляються!
Порядок елементів не має значення.
{A, B, C} = {C, A, B} = {B, C, A}
Всі ці множини однакові!
Елемент або належить множині (∈), або не належить (∉).
Україна ∈ КРАЇНИ
Марс ∉ КРАЇНИ
Декартів добуток
Математична формула:
A × B = {(a, b) | a ∈ A ∧ b ∈ B}
Читається: "Множина всіх пар (a, b) таких, що a належить A та b належить B"
Приклад 1: Прості множини
A = {1, 2, 3}
B = {x, y}
A × B = {
(1, x), (1, y),
(2, x), (2, y),
(3, x), (3, y)
}
Візуалізація:
Кількість елементів:
|A × B| = |A| × |B| = 3 × 2 = 6 pairs
Приклад 2: Бази даних
СТУДЕНТИ = {Іван, Марія, Петро}
ПРЕДМЕТИ = {Математика, Фізика}
СТУДЕНТИ × ПРЕДМЕТИ = {
(Іван, Математика),
(Іван, Фізика),
(Марія, Математика),
(Марія, Фізика),
(Петро, Математика),
(Петро, Фізика)
}
Це всі можливі комбінації студентів та предметів!
Приклад 3: Множинний декартів добуток
A = {a, b}
B = {1, 2}
C = {x, y}
A × B × C = {
(a, 1, x), (a, 1, y),
(a, 2, x), (a, 2, y),
(b, 1, x), (b, 1, y),
(b, 2, x), (b, 2, y)
}
Кількість: 2 × 2 × 2 = 8 елементів
-- Це Декартів добуток!
SELECT * FROM Students, Subjects;
Відношення (Relation)
Що таке відношення?
Простими словами: Відношення - це вибрані пари з декартового добутку, які мають сенс у нашому контексті.
Математично:
R ⊆ D₁ × D₂ × ... × Dₙ
Де:
- R - відношення
- D₁, D₂, ..., Dₙ - домени (множини можливих значень)
- ⊆ - знак "є підмножиною"
Приклад:
ДОМЕН_СТУДЕНТИ = {Іван, Марія, Петро, Оля}
ДОМЕН_ОЦІНКИ = {2, 3, 4, 5}
ДЕКАРТІВ_ДОБУТОК має 4 × 4 = 16 пар
ВІДНОШЕННЯ_ОЦІНКИ = {
(Іван, 5),
(Марія, 4),
(Петро, 3),
(Оля, 5)
}
ВІДНОШЕННЯ_ОЦІНКИ ⊆ ДОМЕН_СТУДЕНТИ × ДОМЕН_ОЦІНКИ
Важливо: Відношення містить тільки осмислені комбінації!
Властивості відношень
{(Іван, 5), (Марія, 4)} = {(Марія, 4), (Іван, 5)}
Рядки в таблиці можна переставляти!
{(Іван, 5), (Іван, 5)} = {(Іван, 5)}
Кожен кортеж унікальний!
(Іван, 5) ≠ (5, Іван)
У парі порядок має значення!
✅ (Іван, 5)
❌ (Іван, {3, 4, 5})
Значення має бути простим, не множиною!
Приклад відношення
Відношення СТУДЕНТИ:
Математичний запис:
СТУДЕНТИ = {
(1, "Іван", "Іваненко", 20),
(2, "Марія", "Коваленко", 19),
(3, "Петро", "Сидоренко", 21)
}
Табличне представлення:
| student_id | first_name | last_name | age |
|---|---|---|---|
| 1 | Іван | Іваненко | 20 |
| 2 | Марія | Коваленко | 19 |
| 3 | Петро | Сидоренко | 21 |
Таблиця - це візуальне представлення відношення.Відношення - теорія, таблиця - практика!
Домени (Domains)
Приклади доменів
ВІКСТУДЕНТА = {16, 17, 18, ..., 99}
ОЦІНКИ = {2, 3, 4, 5}
ЦІНА = {0.00, 0.01, 0.02, ..., 999999.99}
ІМ'Я = {всі можливі імена}
EMAIL = {рядки виду "user@domain.com"}
ТЕЛЕФОН = {рядки виду "+380XXXXXXXXX"}
ДАТА = {1900-01-01, ..., 2100-12-31}
BOOLEAN = {TRUE, FALSE}
СТАТЬ = {Ч, Ж}
Властивості доменів
- Домен має ім'я
- Домен має тип даних
- Домен має можливі значення
- Різні атрибути можуть використовувати один домен
Приклад:
ДОМЕН_ВІК = INTEGER, діапазон [0..150]
АТРИБУТИ:
- вік_студента використовує ДОМЕН_ВІК
- вік_викладача використовує ДОМЕН_ВІК
- вік_батька використовує ДОМЕН_ВІК
Всі три атрибути мають однаковий домен!
Чому домени важливі?
- Цілісність даних - неможливо вставити неправильне значення
- Повторне використання - один домен для багатьох атрибутів
- Зрозумілість - чітко видно, які значення допустимі
- Оптимізація - СУБД може оптимізувати зберігання
Приклад порушення цілісності:
ДОМЕН_ОЦІНКИ = {2, 3, 4, 5}
❌ INSERT INTO Grades VALUES (1, 'Іван', 10); -- 10 не в домені!
✅ INSERT INTO Grades VALUES (1, 'Іван', 5); -- 5 в домені
Кортежі (Tuples)
Структура кортежу
Приклад кортежу:
t = (1, "Іван", "Іваненко", 20, "КНТ-21")
Розбір за позиціями:
| Позиція | Значення | Домен | Атрибут |
|---|---|---|---|
| 1 | 1 | INTEGER | student_id |
| 2 | "Іван" | VARCHAR(50) | first_name |
| 3 | "Іваненко" | VARCHAR(50) | last_name |
| 4 | 20 | INTEGER | age |
| 5 | "КНТ-21" | VARCHAR(10) | group_code |
Арність відношення
Приклади:
КРАЇНИ = {
(Україна),
(Польща),
(Німеччина)
}
Таблиця:
| country_name |
|---|
| Україна |
| Польща |
| Німеччина |
С ТУДЕНТ_ГРУПА = {
(Іван, КНТ-21),
(Марія, КНТ-21),
(Петро, КНТ-22)
}
Таблиця:
| student_name | group_code |
|---|---|
| Іван | КНТ-21 |
| Марія | КНТ-21 |
| Петро | КНТ-22 |
СТУДЕНТИ = {
(1, Іван, Іваненко, 20, КНТ-21),
(2, Марія, Коваленко, 19, КНТ-21)
}
Таблиця:
| id | first_name | last_name | age | group |
|---|---|---|---|---|
| 1 | Іван | Іваненко | 20 | КНТ-21 |
| 2 | Марія | Коваленко | 19 | КНТ-21 |
Потужність відношення
Приклад:
СТУДЕНТИ = {
(1, Іван, Іваненко, 20),
(2, Марія, Коваленко, 19),
(3, Петро, Сидоренко, 21),
(4, Оля, Петренко, 20)
}
Арність = 4 (чотири атрибути)
Потужність = 4 (чотири кортежі/рядки)
Візуалізація:
Атрибути (Attributes)
Типи атрибутів
Прості (Simple, Atomic) атрибути не можна розділити на частини.
Приклади:
age- вік (число)email- адреса електронної поштиrating- рейтинг
student_id: 1
age: 20
email: "ivan@example.com"
Складені (Composite) атрибути можна розділити на частини.
Приклад - ім'я:
full_name = {
first_name: "Іван",
middle_name: "Петрович",
last_name: "Іваненко"
}
У реляційній моделі розбиваємо:
| first_name | middle_name | last_name |
|---|---|---|
| Іван | Петрович | Іваненко |
Похідні (Derived) атрибути обчислюються на основі інших.
Приклад - вік:
birth_date: 2004-03-15
current_date: 2024-03-15
age = current_date.year - birth_date.year = 20
Зберігаємо birth_date, обчислюємо age!
Багатозначні (Multivalued) атрибути мають кілька значень.
Приклад - телефони:
student: Іван
phones: {+380501234567, +380672345678, +380931111111}
У реляційній моделі - окрема таблиця:
| student_id | phone |
|---|---|
| 1 | +380501234567 |
| 1 | +380672345678 |
| 1 | +380931111111 |
Правила атрибутів у реляційній моделі
| student_id | phones |
|---|---|
| 1 | +380501234567, +380672345678 |
| student_id | phone |
|---|---|
| 1 | +380501234567 |
| 1 | +380672345678 |
Ключі (Keys)
Ключі - це фундаментальна концепція реляційноїмоделі. Вони забезпечують унікальність та зв'язки між відношеннями.
Надключ (Superkey)
Приклад:
Таблиця СТУДЕНТИ:
| student_id | first_name | last_name | |
|---|---|---|---|
| 1 | ivan@example.com | Іван | Іваненко |
| 2 | maria@example.com | Марія | Коваленко |
| 3 | petro@example.com | Петро | Сидоренко |
Надключі:
{student_id}
{email}
{student_id, email}
{student_id, first_name}
{student_id, last_name}
{student_id, email, first_name, last_name}
...
Чому це надключі?
Кожна з цих комбінацій унікально ідентифікує рядок!
Candidate Key (Потенційний ключ)
Приклад:
З попередньої таблиці:
Надключі:
{student_id} ← CANDIDATE KEY ✅
{email} ← CANDIDATE KEY ✅
{student_id, email} ← НЕ candidate (можна видалити email)
{student_id, first_name, last_name} ← НЕ candidate (можна видалити first_name і last_name)
Потенційні ключі:
{student_id} - мінімальний
{email} - мінімальний
Візуалізація:
Primary Key (Первинний ключ)
Правила первинного ключа:
- Унікальність - кожне значення унікальне
- Незмінність - не змінюється після створення
- NOT NULL - не може бути NULL
- Один на таблицю - тільки один первинний ключ
Приклад:
CREATE TABLE Students (
student_id INT PRIMARY KEY, -- ← Первинний ключ
email VARCHAR(100) UNIQUE, -- ← Потенційний ключ (альтернативний)
first_name VARCHAR(50),
last_name VARCHAR(50)
);
Потенційні ключі: {student_id}, {email}
Первинний ключ: student_id
Альтернативний ключ: email
Чому обрали student_id?
- Коротший (INT vs VARCHAR(100))
- Швидший для індексування
- Стабільний (email може змінитися)
- Зручний для посилань з інших таблиць
- Довший
- Може змінитися
- Повільніший для JOIN операцій
Composite Key (Складений ключ)
Приклад - зв'язок багато-до-багатьох:
Таблиця ENROLLMENT (студенти та курси):
| student_id | course_id | semester | grade |
|---|---|---|---|
| 1 | 101 | 2024-1 | 5 |
| 1 | 102 | 2024-1 | 4 |
| 2 | 101 | 2024-1 | 5 |
| 2 | 102 | 2024-1 | 3 |
Первинний ключ:
PRIMARY KEY (student_id, course_id, semester)
Чому потрібні всі три?
(student_id)- не унікально (студент бере багато курсів)(course_id)- не унікально (курс беруть багато студентів)(semester)- не унікально (багато записів за семестр)(student_id, course_id, semester)- унікально! ✅
Foreign Key (Зовнішній ключ)
Приклад:
Таблиця Students:
| student_id (PK) | first_name | last_name |
|---|---|---|
| 1 | Іван | Іваненко |
| 2 | Марія | Коваленко |
Таблиця Enrollments:
| enrollment_id (PK) | student_id (FK) | course_name |
|---|---|---|
| 101 | 1 | Математика |
| 102 | 1 | Фізика |
| 103 | 2 | Математика |
CREATE TABLE Enrollments (
enrollment_id INT PRIMARY KEY,
student_id INT,
course_name VARCHAR(100),
FOREIGN KEY (student_id) REFERENCES Students(student_id)
);
Візуалізація зв'язку:
Правила зовнішніх ключів:
- Значення FK має існувати в PK батьківської таблиці, або бути NULL
- При видаленні батьківського запису: - CASCADE - видалити всі дочірні - SET NULL - встановити NULL у дочірніх - RESTRICT - заборонити видалення
Alternate Key (Альтернативний ключ)
Приклад:
CREATE TABLE Users (
user_id INT PRIMARY KEY, -- Первинний ключ
email VARCHAR(100) UNIQUE, -- Альтернативний ключ
phone VARCHAR(20) UNIQUE, -- Альтернативний ключ
username VARCHAR(50) UNIQUE -- Альтернативний ключ
);
Потенційні ключі: {user_id}, {email}, {phone}, {username}
Первинний: user_id
Альтернативні: email, phone, username
In практику:
-- Можна знайти користувача будь-яким способом:
SELECT * FROM Users WHERE user_id = 1;
SELECT * FROM Users WHERE email = 'ivan@example.com';
SELECT * FROM Users WHERE phone = '+380501234567';
SELECT * FROM Users WHERE username = 'ivan_ua';
Порівняльна таблиця ключів
| Тип ключа | Унікан льність | Кількість | NULL дозволений | Використання |
|---|---|---|---|---|
| Superkey | ✅ Так | Багато | ✅ Можливо | Теоретичне поняття |
| Candidate | ✅ Так | 1+ | ❌ Ні | Потенційні ідентифікатори |
| Primary | ✅ Так | 1 | ❌ Ні | Основний ідентифікатор |
| Alternate | ✅ Так | 0+ | ❌ Ні | Додаткові унікальні ідентифікатори |
| Foreign | ❌ Ні | 0+ | ⚠️ Залежить | Зв'язки між таблицями |
| Composite | ✅ Так | Залежить | ❌ Ні | Багатостовпцеві ключі |
Від відношень до таблиць
Еволюція термінології
Едгар Кодд використовував математичні терміни, але на практиці вони еволюціонували:
| Математичний термін | Термін у СУБД | Візуальне представлення |
|---|---|---|
| Відношення (Relation) | Таблиця (Table) | Сітка з рядками та стовпцями |
| Кортеж (Tuple) | Рядок (Row, Record) | Горизонтальний рядок у таблиці |
| Атрибут (Attribute) | Стовпець (Column, Field) | Вертикальний стовпець у таблиці |
| Домен (Domain) | Тип даних (Data Type) | INT, VARCHAR, DATE, etc. |
| Арність (Degree) | Кількість стовпців | Число колонок |
| Потужність (Cardinality) | Кількість рядків | Число записів |
Приклад еволюції:
СТУДЕНТИ = {
t₁ = (1, "Іван", "Іваненко", 20),
t₂ = (2, "Марія", "Коваленко", 19),
t₃ = (3, "Петро", "Сидоренко", 21)
}
Арність = 4
Потужність = 3
CREATE TABLE Students (
student_id INT PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
age INT
);
-- 4 стовпці, 3 рядки
| student_id | first_name | last_name | age |
|---|---|---|---|
| 1 | Іван | Іваненко | 20 |
| 2 | Марія | Коваленко | 19 |
| 3 | Петро | Сидоренко | 21 |
Чому зміна термінології?
1980-ті: Розробники СУБД почали використовувати "таблиця", "рядок"
Сьогодні: Обидві термінології співіснуютьПричини зміни:
- "Таблиця" інтуїтивно зрозуміліша
- Легше пояснювати клієнтам
- Візуальна аналогія очевидна
Важливо розуміти обидві:
- Математична - для розуміння теорії
- Практична - для роботи з SQL
NULL значення
NULL ≠ Порожнє значення
age = NULL
Значення невідоме. Може бути 20, 30, 50 - ми не знаємо!
age = 0
Значення відоме і дорівнює нулю (немовля).
email = ''
Значення відоме - це порожній рядок.
name = ' '
Значення відоме - це рядок з пробілом.
Три-значна логіка (Three-Valued Logic)
У реляційній моделі логічні вирази можуть мати три значення:
Вираз істинний.
SELECT * FROM Students WHERE age > 18;
-- Повертає студентів старше 18
Вираз хибний.
SELECT * FROM Students WHERE age < 16;
-- Не повертає нікого, якщо всі старші
Вираз невідомий (через NULL).
SELECT * FROM Students WHERE age > 18;
-- Якщо age = NULL, результат UNKNOWN
-- Рядок НЕ буде включено в результат!
Правила обчислення:
| Вираз | age = 20 | age = 15 | age = NULL |
|---|---|---|---|
age > 18 | TRUE | FALSE | UNKNOWN |
age < 25 | TRUE | TRUE | UNKNOWN |
age = NULL | FALSE | FALSE | UNKNOWN |
age IS NULL | FALSE | FALSE | TRUE |
age IS NOT NULL | TRUE | TRUE | FALSE |
= NULL або != NULL!❌ Неправильно:SELECT * FROM Students WHERE age = NULL; -- завжди порожній результат!
SELECT * FROM Students WHERE age IS NULL;
Логічні операції з NULL
AND (І):
| A | B | A AND B |
|---|---|---|
| TRUE | TRUE | TRUE |
| TRUE | FALSE | FALSE |
| TRUE | UNKNOWN | UNKNOWN |
| FALSE | UNKNOWN | FALSE |
| UNKNOWN | UNKNOWN | UNKNOWN |
OR (АБО):
| A | B | A OR B |
|---|---|---|
| TRUE | TRUE | TRUE |
| TRUE | FALSE | TRUE |
| TRUE | UNKNOWN | TRUE |
| FALSE | UNKNOWN | UNKNOWN |
| UNKNOWN | UNKNOWN | UNKNOWN |
NOT (НЕ):
| A | NOT A |
|---|---|
| TRUE | FALSE |
| FALSE | TRUE |
| UNKNOWN | UNKNOWN |
Приклад:
-- age = NULL, grade = 5
SELECT * FROM Students
WHERE age > 18 AND grade > 4;
-- age > 18 = UNKNOWN
-- grade > 4 = TRUE
-- UNKNOWN AND TRUE = UNKNOWN
-- Рядок НЕ буде включено!
Реляційна алгебра
Реляційна алгебра - це математична основа SQL!
Основні операції
Вибір стовпців
Позначення: π (грецька літера "пі")
Синтаксис:
π_{A₁, A₂, ..., Aₙ}(R)
Приклад:
СТУДЕНТИ:
| student_id | first_name | last_name | age |
|------------|------------|-----------|-----|
| 1 | Іван | Іваненко | 20 |
| 2 | Марія | Коваленко | 19 |
π_{first_name, age}(СТУДЕНТИ) =
| first_name | age |
|------------|-----|
| Іван | 20 |
| Марія | 19 |
SQL еквівалент:
SELECT first_name, age FROM Students;
Вибір рядків за умовою
Позначення: σ (грецька літера "сігма")
Синтаксис:
σ_{умова}(R)
Приклад:
σ_{age > 19}(СТУДЕНТИ) =
| student_id | first_name | last_name | age |
|------------|------------|-----------|-----|
| 1 | Іван | Іваненко | 20 |
| 3 | Петро | Сидоренко | 21 |
SQL еквівалент:
SELECT * FROM Students WHERE age > 19;
Об'єднання двох відношень
Позначення: ∪
Умова: Відношення мають однакову структуру
Приклад:
СТУДЕНТИ_КНТ21:
| name |
|-------|
| Іван |
| Марія |
СТУДЕНТИ_КНТ22:
| name |
|-------|
| Петро |
| Марія |
СТУДЕНТИ_КНТ21 ∪ СТУДЕНТИ_КНТ22 =
| name |
|-------|
| Іван |
| Марія | ← дублікат видалено!
| Петро |
SQL еквівалент:
SELECT name FROM Students_KNT21
UNION
SELECT name FROM Students_KNT22;
Видалення з першого відношення рядків, які є в другому
Позначення: − або \
Приклад:
ВСІСТУДЕНТИ:
| name |
|-------|
| Іван |
| Марія |
| Петро |
ВИПУСКНИКИ:
| name |
|-------|
| Марія |
ВСІСТУДЕНТИ − ВИПУСКНИКИ =
| name |
|-------|
| Іван |
| Петро |
SQL еквівалент:
SELECT name FROM AllStudents
EXCEPT
SELECT name FROM Graduates;
Всі можливі комбінації рядків двох відношень
Позначення: ×
Приклад:
СТУДЕНТИ:
| name |
|-------|
| Іван |
| Марія |
ПРЕДМЕТИ:
| subject |
|-------------|
| Математика |
| Фізика |
СТУДЕНТИ × ПРЕДМЕТИ =
| name | subject |
|-------|------------|
| Іван | Математика |
| Іван | Фізика |
| Марія | Математика |
| Марія | Фізика |
SQL еквівалент:
SELECT * FROM Students, Subjects;
-- або
SELECT * FROM Students CROSS JOIN Subjects;
Поєднання рядків за умовою
Позначення: ⋈
Синтаксис:
R ⋈_{умова} S
Приклад:
СТУДЕНТИ:
| student_id | name |
|------------|-------|
| 1 | Іван |
| 2 | Марія |
ОЦІНКИ:
| student_id | subject | grade |
|------------|------------|-------|
| 1 | Математика | 5 |
| 1 | Фізика | 4 |
| 2 | Математика | 5 |
СТУДЕНТИ ⋈_{студенти.student_id = оцінки.student_id} ОЦІНКИ =
| student_id | name | subject | grade |
|------------|-------|------------|-------|
| 1 | Іван | Математика | 5 |
| 1 | Іван | Фізика | 4 |
| 2 | Марія | Математика | 5 |
SQL еквівалент:
SELECT s.student_id, s.name, g.subject, g.grade
FROM Students s
JOIN Grades g ON s.student_id = g.student_id;
Композиція операцій
Операції можна комбінувати!
Приклад: Знайти імена студентів старше 19 років
Реляційна алгебра:
π_{first_name}(σ_{age > 19}(СТУДЕНТИ))
Крок 1: σ*{age > 19}(СТУДЕНТИ) - вибрати студентів старше 19
Крок 2: π*(...) - взяти тільки імена
SQL:
SELECT first_name
FROM Students
WHERE age > 19;
Складніший приклад:
Завдання: Знайти імена студентів, які отримали оцінку 5 з математики
Реляційна алгебра:
π_{name}(
σ_{grade = 5 AND subject = 'Математика'}(
СТУДЕНТИ ⋈_{student_id} ОЦІНКИ
)
)
SQL:
SELECT s.name
FROM Students s
JOIN Grades g ON s.student_id = g.student_id
WHERE g.grade = 5 AND g.subject = 'Математика';
Практичні приклади
Приклад 1: Бібліотека
Відношення BOOKS:
BOOKS = {
(1, "Кобзар", "Тарас Шевченко", 1840),
(2, "Лісова пісня", "Леся Українка", 1911),
(3, "Захар Беркут", "Іван Франко", 1883)
}
Домени:
- book_id ∈ INTEGER
- title ∈ VARCHAR(200)
- author ∈ VARCHAR(100)
- year ∈ INTEGER 1000..2100
Таблиця:
| book_id (PK) | title | author | year |
|---|---|---|---|
| 1 | Кобзар | Тарас Шевченко | 1840 |
| 2 | Лісова пісня | Леся Українка | 1911 |
| 3 | Захар Беркут | Іван Франко | 1883 |
Операції:
π_{title}(BOOKS) =
| title |
|---------------|
| Кобзар |
| Лісова пісня |
| Захар Беркут |
σ_{year > 1900}(BOOKS) =
| book_id | title | author | year |
|---------|--------------|---------------|------|
| 2 | Лісова пісня | Леся Українка | 1911 |
π_{author}(σ_{year > 1900}(BOOKS)) =
| author |
|---------------|
| Леся Українка |
Приклад 2: Університет
Три відношення:
STUDENTS:
| student_id (PK) | name | group_id (FK) |
|---|---|---|
| 1 | Іван | 101 |
| 2 | Марія | 101 |
| 3 | Петро | 102 |
GROUPS:
| group_id (PK) | group_name | faculty |
|---|---|---|
| 101 | КНТ-21 | КН |
| 102 | КНТ-22 | КН |
ENROLLMENTS:
| student_id (FK) | course | grade |
|---|---|---|
| 1 | Math | 5 |
| 1 | Physics | 4 |
| 2 | Math | 5 |
| 3 | Physics | 3 |
Запит: Знайти назви груп студентів, які отрим али 5 з математики
Реляційна алгебра:
π_{group_name}(
GROUPS ⋈_{group_id} (
STUDENTS ⋈_{student_id} (
σ_{course='Math' AND grade=5}(ENROLLMENTS)
)
)
)
Крок 1: Вибрати оцінки 5 з Math
σ_{course='Math' AND grade=5}(ENROLLMENTS)
| student_id | course | grade |
|------------|--------|-------|
| 1 | Math | 5 |
| 2 | Math | 5 |
Крок 2: Приєднати студентів
| student_id | name | group_id |
|------------|-------|----------|
| 1 | Іван | 101 |
| 2 | Марія | 101 |
Крок 3: Приєднати групи
| student_id | name | group_id | group_name |
|------------|-------|----------|------------|
| 1 | Іван | 101 | КНТ-21 |
| 2 | Марія | 101 | КНТ-21 |
Крок 4: Проекція (тільки назви груп)
| group_name |
|------------|
| КНТ-21 |
SQL:
SELECT DISTINCT g.group_name
FROM Groups g
JOIN Students s ON g.group_id = s.group_id
JOIN Enrollments e ON s.student_id = e.student_id
WHERE e.course = 'Math' AND e.grade = 5;
Висновки
✅ Відношення: структура, властивості, домени
✅ Кортежі та атрибути: арність, потужність, типи атрибутів
✅ Ключі: надключ, потенційний, первинний, зовнішній, складений
✅ NULL значення: три-значна логіка
✅ Реляційна алгебра: проекція, вибірка, об'єднання, з'єднання
✅ Еволюція: від відношень до таблиць
Ключові концепції:
- Математична строгість - основа надійності реляційної моделі
- Ключі - забезпечують унікальність та зв'язки
- NULL - потребує особливої уваги (три-значна логіка)
- Реляційна алгебра - теоретична основа SQL
Навіщо це все?
- Проектувати правильні структури БД
- Оптимізувати запити
- Розуміти роботу СУБД "під капотом"
- Уникати помилок з NULL
- Обирати правильні ключі
У наступному уроці:
Ми вивчимо ER-моделювання - як від вимог до проєкту перейти до структури бази даних!
Практичні завдання
Завдання 1: Домени та відношення
Створіть відношення EMPLOYEES зі структурою:
Домени:
- employee_id: INTEGER 1..9999
- full_name: VARCHAR(100)
- position: {Менеджер, Розробник, Дизайнер, Тестувальник}
- salary: DECIMAL 0..999999.99
- hire_date: DATE 2000-01-01..2100-12-31
Оберіть:
- Які атрибути є потенційними ключами?
- Який атрибут обрати як первинний ключ?
- Чи можуть атрибути мати NULL?
Завдання 2: Ключі
Дано таблиця ORDERS:
| order_id | customer_email | order_date | total |
|---|---|---|---|
| 1 | ivan@example.com | 2024-01-15 | 500 |
| 2 | maria@example.com | 2024-01-16 | 750 |
| 3 | ivan@example.com | 2024-01-17 | 300 |
Питання:
- Які надключі існують?
- Які потенційні ключі?
- Який первинний ключ обрати?
- Чи є складені ключі?
Завдання 3: Реляційна алгебра
Дані дві таблиці:
STUDENTS:
| student_id | name | age |
|---|---|---|
| 1 | Іван | 20 |
| 2 | Марія | 19 |
| 3 | Петро | 21 |
GRADES:
| student_id | subject | grade |
|---|---|---|
| 1 | Math | 5 |
| 2 | Math | 4 |
| 1 | Physics | 4 |
| 3 | Math | 5 |
Напишіть в реляційній алгебрі:
- Імена студентів старше 19
- Предмети, з яких хтось отримав 5
- Імена студентів, які отримали 5 з Math
Завдання 4: NULL логіка
Обчисліть результат:
age = NULL
grade = 5
1. age > 18 AND grade > 4 = ?
2. age <20 OR grade = 5 = ?
3. NOT (age IS NULL) = ?
4. age = NULL AND grade = 5 = ?
- UNKNOWN (UNKNOWN AND TRUE = UNKNOWN)
- TRUE (UNKNOWN OR TRUE = TRUE)
- FALSE (NOT TRUE = FALSE, бо age IS NULL = TRUE)
- UNKNOWN (UNKNOWN AND TRUE = UNKNOWN)