Ответ
Основные сущности и их связи:
CinemaHall(Кинозал) — хранит информацию о зале.id(PK),name,total_rows,seats_per_row
Seat(Место) — конкретное кресло в зале.id(PK),hall_id(FK → CinemaHall),row_number,seat_number,type(например, 'STANDARD', 'VIP')
Movie(Фильм) — каталог фильмов.id(PK),title,duration_minutes,rating,description
Screening(Сеанс) — событие показа фильма в определённом зале.id(PK),movie_id(FK → Movie),hall_id(FK → CinemaHall),start_time,base_price
Ticket(Билет) — факт бронирования/покупки места на сеанс.id(PK),screening_id(FK → Screening),seat_id(FK → Seat),status('RESERVED', 'PURCHASED'),user_id,purchase_time
Пример DDL (PostgreSQL):
CREATE TABLE cinema_hall (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
total_rows INT NOT NULL CHECK (total_rows > 0),
seats_per_row INT NOT NULL CHECK (seats_per_row > 0)
);
CREATE TABLE seat (
id SERIAL PRIMARY KEY,
hall_id INT NOT NULL REFERENCES cinema_hall(id) ON DELETE CASCADE,
row_number INT NOT NULL,
seat_number INT NOT NULL,
type VARCHAR(20) DEFAULT 'STANDARD',
UNIQUE(hall_id, row_number, seat_number)
);
CREATE TABLE movie (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
duration_minutes INT NOT NULL CHECK (duration_minutes > 0),
rating VARCHAR(10),
description TEXT
);
CREATE TABLE screening (
id SERIAL PRIMARY KEY,
movie_id INT NOT NULL REFERENCES movie(id),
hall_id INT NOT NULL REFERENCES cinema_hall(id),
start_time TIMESTAMP NOT NULL,
base_price DECIMAL(10,2) NOT NULL CHECK (base_price >= 0),
UNIQUE(hall_id, start_time) -- Предотвращает наложение сеансов в одном зале
);
CREATE TABLE ticket (
id SERIAL PRIMARY KEY,
screening_id INT NOT NULL REFERENCES screening(id),
seat_id INT NOT NULL REFERENCES seat(id),
status VARCHAR(20) NOT NULL,
user_id INT, -- Ссылка на таблицу пользователей
purchase_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(screening_id, seat_id) -- Гарантирует уникальность места на сеансе
);
Рекомендуемые индексы для производительности:
CREATE INDEX idx_screening_time ON screening(start_time);
CREATE INDEX idx_screening_movie ON screening(movie_id);
CREATE INDEX idx_ticket_screening ON ticket(screening_id);
CREATE INDEX idx_ticket_user ON ticket(user_id);
Почему такая схема? Она нормализована, минимизирует избыточность данных и обеспечивает целостность через внешние ключи. Уникальные ограничения предотвращают логические ошибки (два сеанса в одном зале одновременно, двойная продажа одного места).