От модели к SQL: создаём схему
Превращаем нарисованную модель в работающие таблицы
Вы спроектировали базу: придумали сущности, их атрибуты и связи между ними. На бумаге всё красиво — прямоугольники, стрелки, ключи. Но база данных не понимает картинок. Чтобы схема ожила, её нужно записать на языке, который понимает СУБД. Этот язык — SQL, а точнее его часть, отвечающая за описание структуры.
Перевод модели в SQL — это запись каждой сущности как таблицы (
CREATE TABLE), каждого атрибута как столбца с типом, и каждой связи как внешнего ключа (FOREIGN KEY). Ограничения вродеPRIMARY KEYиNOT NULLпереносят правила модели в код, который СУБД будет соблюдать сама.
Зачем вообще переводить модель в код
Можно ли просто начать вставлять данные? Нет: пока нет таблицы, данные некуда класть. Но дело не только в этом. Когда вы описываете структуру явно, СУБД берёт на себя контроль качества. Она не позволит создать ученика без имени, не даст двум ученикам один и тот же идентификатор и не примет оценку, которая ссылается на несуществующий класс. Ваша модель из набора договорённостей превращается в правила, которые невозможно нарушить.
Четыре кирпичика описания таблицы
Любой CREATE TABLE собирается из одних и тех же элементов. Разберём их на сущности «Ученик».
| Элемент | Что задаёт | Пример |
|---|---|---|
| Имя столбца | как называется атрибут | student_name |
| Тип данных | какие значения допустимы | TEXT, INTEGER |
PRIMARY KEY | уникальный идентификатор строки | student_id INTEGER PRIMARY KEY |
NOT NULL | значение обязательно | student_name TEXT NOT NULL |
Как выбрать тип столбца
Тип — это обещание: «здесь будут только такие значения». В SQLite базовых типов немного, и для школьной базы их хватает с запасом.
| Атрибут модели | Тип в SQL | Почему |
|---|---|---|
| Идентификатор, год, балл | INTEGER | целые числа, по ним удобно искать и сравнивать |
| Имя, название класса | TEXT | произвольный текст |
| Дата выставления оценки | TEXT (формат ГГГГ-ММ-ДД) | в SQLite даты хранят строкой, и они корректно сортируются |
| Средний балл | REAL | дробное число |
Правило простое: по чему считаем и сравниваем как числа — то число (
INTEGER/REAL); что просто храним и показываем — то текст (TEXT). Номер телефона, кстати, тоже текст: с ним не делают арифметику, а ведущий ноль терять нельзя.
От ER-модели школы к таблицам
Возьмём знакомую школьную модель с тремя сущностями и связями между ними.
| Сущность | Атрибуты | Связь |
|---|---|---|
| Класс | id, название | — |
| Ученик | id, имя, id класса | каждый ученик принадлежит одному классу |
| Оценка | id, id ученика, предмет, балл, дата | каждая оценка принадлежит одному ученику |
Связи на схеме — это стрелки «многие к одному»: много учеников в одном классе, много оценок у одного ученика. В SQL такая стрелка превращается во внешний ключ: столбец в «дочерней» таблице, который ссылается на PRIMARY KEY «родительской».
Порядок создания таблиц решает всё
Внешний ключ не может ссылаться на таблицу, которой ещё нет. Поэтому действует железное правило.
Сначала создаём те таблицы, на которые ссылаются; потом — те, что ссылаются. Идём «от родителей к детям»: сперва
classes, затемstudents(ссылается на классы), и последней —grades(ссылается на учеников.)
Если перепутать порядок и создать students раньше classes, СУБД пожалуется, что не знает таблицы, на которую вы ссылаетесь. Та же логика и при удалении, только наоборот: сначала уходят «дети», потом «родители».
Собираем всё вместе и проверяем
Ниже — полная схема школьной базы: три CREATE TABLE в правильном порядке, демо-данные и проверочный запрос с JOIN, который собирает имя ученика, его класс и оценку в одну строку. Запустите блок и посмотрите, что вернёт финальный SELECT.
-- 1. Родительская таблица: классы (на неё ссылаются)
CREATE TABLE classes (
class_id INTEGER PRIMARY KEY,
class_name TEXT NOT NULL
);
-- 2. Ученики: ссылаются на классы
CREATE TABLE students (
student_id INTEGER PRIMARY KEY,
student_name TEXT NOT NULL,
class_id INTEGER REFERENCES classes(class_id)
);
-- 3. Оценки: ссылаются на учеников (создаём последней)
CREATE TABLE grades (
grade_id INTEGER PRIMARY KEY,
student_id INTEGER NOT NULL REFERENCES students(student_id),
subject TEXT NOT NULL,
score INTEGER NOT NULL,
grade_date TEXT
);
-- Демо-данные: тоже от родителей к детям
INSERT INTO classes (class_id, class_name) VALUES
(1, '9-А'),
(2, '9-Б');
INSERT INTO students (student_id, student_name, class_id) VALUES
(1, 'Аня Орлова', 1),
(2, 'Борис Ким', 1),
(3, 'Вера Лосева', 2);
INSERT INTO grades (grade_id, student_id, subject, score, grade_date) VALUES
(1, 1, 'Математика', 5, '2026-04-10'),
(2, 1, 'Физика', 4, '2026-04-12'),
(3, 2, 'Математика', 3, '2026-04-10'),
(4, 3, 'Физика', 5, '2026-04-12');
-- Проверка: имя ученика + класс + оценка в одной строке
SELECT s.student_name,
c.class_name,
g.subject,
g.score
FROM grades AS g
JOIN students AS s ON s.student_id = g.student_id
JOIN classes AS c ON c.class_id = s.class_id
ORDER BY s.student_name, g.subject;В результате — четыре строки, по одной на каждую оценку. У Ани Орловой две строки (математика и физика), потому что у неё две оценки, и в обеих верно подставился класс «9-А». Это и есть доказательство, что связи описаны правильно: JOIN прошёл по внешним ключам и нигде не «потерял» данные.
| student_name | class_name | subject | score |
|---|---|---|---|
| Аня Орлова | 9-А | Математика | 5 |
| Аня Орлова | 9-А | Физика | 4 |
| Борис Ким | 9-А | Математика | 3 |
| Вера Лосева | 9-Б | Физика | 5 |
Частые ошибки
- Неверный порядок таблиц. Создавать
studentsдоclasses— ошибка: внешний ключ ссылается на ещё несуществующую таблицу.- Забыли
NOT NULLтам, где значение обязательно. Тогда в базу проскользнёт ученик без имени или оценка без балла.- Идентификатор как
TEXT. По числовомуidискать и связывать быстрее и надёжнее; текст оставляйте для имён и названий.- Дата как «13.04.2026». Храните в формате
ГГГГ-ММ-ДД— только так строки-даты сортируются по-настоящему по времени.
Коротко
Сущность становится таблицей через CREATE TABLE, атрибут — столбцом с подходящим типом, связь «многие к одному» — внешним ключом, который ссылается на PRIMARY KEY родителя. Обязательность атрибута фиксирует NOT NULL, уникальность строки — PRIMARY KEY. Создаём таблицы от родителей к детям, удаляем — наоборот. Проверяем результат запросом с JOIN: если данные собираются в осмысленные строки и ничего не теряется, значит, модель переведена в SQL верно.