Проектирование базы данных для маленьких на примере кинотеатра. Часть 1 - базовые таблицы
Пред тем как начать строить базу данных мы должны разобраться в структуре нашего бизнеса. Допустим наш кинотеатр имеет несколько залов. Каждый зал характеризуется названием, количеством мест, типом экрана (обычный или стерео) возможно в дальнейшем мы выявим другие необходимые нам параметры залов, но для начала этого будет достаточно.
Создадим таблицу halls
, в данной статье для примеров я буду использовать синтаксис PostgreSQL поэтому первый запрос будет следующим:
create table halls ( id serial primary key, name text, seats_count int, screen_type ? );
Рассмотрим структуру подробнее:
- id имеет тип serial - это самый простой способ использовать авто инкремент кроме этого поле будет являться первичным ключом к строкам таблицы. (Надеюсь это понятно. Если нет пишите в комментах)
- name типа text если вы будете писать для MySQL, то скорее всего вам стоит использовать varchar, но в PostgreSQL эти типы почти идентичны, а само слово text короче
- seats_count - integer как же иначе? К тому же нам скорее всего придётся выполнять арифметические операции над этим полем (например посчитать суммарную вместимость залов)
(если вы заметили я придерживаюсь snake notation в названии столбцов. Это не принципиально если Вам больше нравится camelCase Вы вольны использовать её, только будьте последовательны и не смешивайте разные типы в одном проекте)
- screen_type - тут я поставил знак вопроса. Почему? Дело в том что я могу использовать тип text и заносить строки 'regular' или 'stereo' могу создать свой тип данных состоящий из этих двух значений или создать дополнительную таблицу - справочник.
create table halls ( id serial primary key, name text, seats_count int, screen_type text check (screen_type in ('regular', 'stereo')) ); insert into halls (name, seats_count, screen_type) values ('Blue', 25, 'regular'); insert into halls (name, seats_count, screen_type) values ('Gold', 15, '3d'); select * from halls;
Если Вы проверите данный код на SQLize.online то увидите что данная конструкция предотвращает вставку неправильных значений. Недостатком такого подхода является что для добавления нового типа зала потребуется менять структуру таблицы. В нашем случае удалять и создавать заново ограничение колонки:
alter table halls drop constraint halls_screen_type_check ; alter table halls add constraint halls_screen_type_check check (screen_type in ('regular', 'stereo', '3d'));
- другой способ - использовать таблицу справочник. В этом случае сначала создаем таблицу screen_types заносим в неё строки 'regular' и 'stereo' а в таблице залов будем использовать числовое поле
screen_type
связанное внешним ключом со справочником:
create table screen_types ( id serial primary key, name text ); insert into screen_types (name) values ('regular'), ('stereo'); create table halls ( id serial primary key, name text, seets_count int, screen_type int references screen_types(id) );
В этом варианте мы не имеем проблем с добавлением типа экрана, однако при добавлении зала должны помнить числовые индексы типов экранов и при выборке данных использовать `join`
insert into halls (name, seets_count, screen_type) values ('Blue', 25, 1); insert into halls (name, seets_count, screen_type) values ('Gold', 15, 2); select halls.id, halls.name, seets_count, screen_types.name as screen_type from halls join screen_types on screen_types.id = halls.screen_type;
CREATE TYPE screen_type AS ENUM ('regular', 'stereo', '3d'); create table halls ( id serial primary key, name text, seets_count int, screen_type screen_type ); insert into halls (name, seets_count, screen_type) values ('Blue', 25, 'regualr'); insert into halls (name, seets_count, screen_type) values ('Gold', 15, '3d'); select * from halls;
Добавление нового типа выполняется командой `alter type`
alter type screen_type add value '4d';
Снова напомню что все вышеприведенные запросы могут быть проверенны онлайн на SQLize.online
Выбор варианта зависит от нескольких причин. Как часто прогнозируется изменение типов, как много типов планируется иметь в базе и даже от Вашего опыта работы. Вариант с таблицей справочником - универсальный. Я в нашем случае остановлюсь на варианте текста с ограничением.
(типы экранов практически не меняются, если нужно будет добавить тип, то таблица залов будет содержать не более десятка залов, и ее изменение не займет много времени зато я получу экономию на объединениях таблиц)
Если Вы не согласны с моим выбором - добро пожаловать в комменты
А мы продолжаем. Следующим базовым компонентом являются фильмы.
create table films ( id serial primary key, -- первичный ключ title text, -- название фильма description text, -- краткое описание, сюжет release_year int, -- год выхода на экран duration int, -- длительность в минутах director int, genre int );
Если первые 5 полей вопросов не вызывают то что скажете по поводу режиссера? Я надеюсь Вы ответили - создаем таблицу справочник + внешний ключ. Я предлагаю назвать таблицу persons . Почему не directors
спросите вы. Потому что возможно мы будем хранить список актеров и может оказаться что один и тот же человек будет выступать в нескольких ролях. Так что это некий задел на будущее.
Так что создадим таблицу persons
и не забудем задать ограничение в виде внешнего ключа между таблицами:
create table persons ( id serial primary key, name text, year_of_birth int ); alter table films add constraint film_director_fk foreign key (director) references persons(id);
Теперь посмотрим на поле genre
Вы можете сказать поступим так же как с режиссерами. Однако я возражу, что редко какой фильм можно отнести к одной категории поэтому мы построим отношение многие ко многим. Один фильм может относиться к нескольким категориям, и естественно к каждой категории относятся множество фильмов.
Создадим таблицу жанров и связующую таблицу между жанрами и фильмами:
create table genres ( id serial primary key, genre text ); create table film_genres ( film int references films(id), genre int references genres(id), primary key (film, genre) );
Обратите внимание в таблице film_genres первичным ключом будет сочетание двух полей film и genre
После этого мы можем удалить столбец genre
из таблицы films:
alter table films drop column genre;
Таким образом мы формально закрепили данные о кинозалах и фильмах в структуре таблиц. Напишите в комментариях если Вам интересно продолжение темы и подписывайтесь на мой блог чтобы не пропустить обновления.