Загрузка данных


-- ============================================================
-- БАЗА ДАННЫХ УЧЕБНОГО РАСПИСАНИЯ
-- СУБД: MySQL 8.0+
-- Кодировка: utf8mb4
-- ============================================================

DROP DATABASE IF EXISTS `учебное_расписание`;

CREATE DATABASE `учебное_расписание`
    CHARACTER SET utf8mb4
    COLLATE utf8mb4_unicode_ci;

USE `учебное_расписание`;


-- ============================================================
-- 1. ФАКУЛЬТЕТЫ
-- ============================================================

CREATE TABLE `факультет` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `название` VARCHAR(200) NOT NULL,

    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_факультет_название` (`название`)
) ENGINE=InnoDB;


-- ============================================================
-- 2. ПРЕПОДАВАТЕЛИ
-- ============================================================

CREATE TABLE `преподаватель` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `факультет_id` BIGINT UNSIGNED NOT NULL,

    `фамилия` VARCHAR(100) NOT NULL,
    `имя` VARCHAR(100) NOT NULL,
    `отчество` VARCHAR(100) NULL,
    `email` VARCHAR(255) NULL,

    PRIMARY KEY (`id`),

    UNIQUE KEY `uk_преподаватель_email` (`email`),

    KEY `idx_преподаватель_факультет`
        (`факультет_id`),

    CONSTRAINT `fk_преподаватель_факультет`
        FOREIGN KEY (`факультет_id`)
        REFERENCES `факультет` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE
) ENGINE=InnoDB;


-- ============================================================
-- 3. ДИСЦИПЛИНЫ
-- ============================================================

CREATE TABLE `дисциплина` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `код` VARCHAR(50) NOT NULL,
    `название` VARCHAR(255) NOT NULL,

    `тип` ENUM(
        'лекция',
        'практика',
        'лабораторная',
        'семинар',
        'экзамен',
        'зачёт'
    ) NOT NULL,

    `количество_часов` INT UNSIGNED NULL,

    PRIMARY KEY (`id`),

    UNIQUE KEY `uk_дисциплина_код` (`код`),

    CONSTRAINT `chk_дисциплина_часы`
        CHECK (
            `количество_часов` IS NULL
            OR `количество_часов` > 0
        )
) ENGINE=InnoDB;


-- ============================================================
-- 4. УЧЕБНЫЕ ГРУППЫ
-- ============================================================

CREATE TABLE `группа` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `название` VARCHAR(100) NOT NULL,

    `курс` TINYINT UNSIGNED NOT NULL,

    `количество_студентов` INT UNSIGNED NOT NULL DEFAULT 0,

    PRIMARY KEY (`id`),

    UNIQUE KEY `uk_группа_название` (`название`),

    CONSTRAINT `chk_группа_курс`
        CHECK (`курс` BETWEEN 1 AND 6)
) ENGINE=InnoDB;


-- ============================================================
-- 5. ПОДГРУППЫ
-- ============================================================

CREATE TABLE `подгруппа` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `группа_id` BIGINT UNSIGNED NOT NULL,

    `название` VARCHAR(100) NOT NULL,

    `количество_студентов` INT UNSIGNED NULL,

    PRIMARY KEY (`id`),

    UNIQUE KEY `uk_подгруппа`
        (`группа_id`, `название`),

    KEY `idx_подгруппа_группа`
        (`группа_id`),

    CONSTRAINT `fk_подгруппа_группа`
        FOREIGN KEY (`группа_id`)
        REFERENCES `группа` (`id`)
        ON DELETE CASCADE
        ON UPDATE CASCADE
) ENGINE=InnoDB;


-- ============================================================
-- 6. СВЯЗЬ ДИСЦИПЛИН И ПРЕПОДАВАТЕЛЕЙ
-- ============================================================

CREATE TABLE `дисциплина_преподаватель` (
    `дисциплина_id` BIGINT UNSIGNED NOT NULL,
    `преподаватель_id` BIGINT UNSIGNED NOT NULL,

    PRIMARY KEY (
        `дисциплина_id`,
        `преподаватель_id`
    ),

    CONSTRAINT `fk_дп_дисциплина`
        FOREIGN KEY (`дисциплина_id`)
        REFERENCES `дисциплина` (`id`)
        ON DELETE CASCADE
        ON UPDATE CASCADE,

    CONSTRAINT `fk_дп_преподаватель`
        FOREIGN KEY (`преподаватель_id`)
        REFERENCES `преподаватель` (`id`)
        ON DELETE CASCADE
        ON UPDATE CASCADE
) ENGINE=InnoDB;


-- ============================================================
-- 7. СВЯЗЬ ДИСЦИПЛИН И ГРУПП
-- ============================================================

CREATE TABLE `дисциплина_группа` (
    `дисциплина_id` BIGINT UNSIGNED NOT NULL,
    `группа_id` BIGINT UNSIGNED NOT NULL,

    PRIMARY KEY (
        `дисциплина_id`,
        `группа_id`
    ),

    CONSTRAINT `fk_дг_дисциплина`
        FOREIGN KEY (`дисциплина_id`)
        REFERENCES `дисциплина` (`id`)
        ON DELETE CASCADE
        ON UPDATE CASCADE,

    CONSTRAINT `fk_дг_группа`
        FOREIGN KEY (`группа_id`)
        REFERENCES `группа` (`id`)
        ON DELETE CASCADE
        ON UPDATE CASCADE
) ENGINE=InnoDB;


-- ============================================================
-- 8. АУДИТОРИИ
-- ============================================================

CREATE TABLE `аудитория` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `корпус` VARCHAR(100) NOT NULL,

    `номер` VARCHAR(30) NOT NULL,

    `вместимость` INT UNSIGNED NOT NULL,

    `тип` ENUM(
        'обычная',
        'лекционная',
        'компьютерный класс',
        'лаборатория',
        'спортивный зал'
    ) NOT NULL DEFAULT 'обычная',

    PRIMARY KEY (`id`),

    UNIQUE KEY `uk_аудитория`
        (`корпус`, `номер`),

    CONSTRAINT `chk_аудитория_вместимость`
        CHECK (`вместимость` > 0)
) ENGINE=InnoDB;


-- ============================================================
-- 9. СЕМЕСТРЫ
-- ============================================================

CREATE TABLE `семестр` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `название` VARCHAR(100) NOT NULL,

    `дата_начала` DATE NOT NULL,
    `дата_окончания` DATE NOT NULL,

    PRIMARY KEY (`id`),

    CONSTRAINT `chk_семестр_даты`
        CHECK (`дата_начала` < `дата_окончания`)
) ENGINE=InnoDB;


-- ============================================================
-- 10. ВРЕМЕННЫЕ СЛОТЫ
-- ============================================================

CREATE TABLE `временной_слот` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `номер_пары` TINYINT UNSIGNED NOT NULL,

    `день_недели` TINYINT UNSIGNED NOT NULL,

    `время_начала` TIME NOT NULL,
    `время_окончания` TIME NOT NULL,

    PRIMARY KEY (`id`),

    UNIQUE KEY `uk_временной_слот`
        (`день_недели`, `номер_пары`),

    CONSTRAINT `chk_слот_номер`
        CHECK (`номер_пары` BETWEEN 1 AND 10),

    CONSTRAINT `chk_слот_день`
        CHECK (`день_недели` BETWEEN 1 AND 7),

    CONSTRAINT `chk_слот_время`
        CHECK (`время_начала` < `время_окончания`)
) ENGINE=InnoDB;


-- ============================================================
-- 11. ДОСТУПНОСТЬ ПРЕПОДАВАТЕЛЕЙ
-- ============================================================

CREATE TABLE `доступность_преподавателя` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `преподаватель_id` BIGINT UNSIGNED NOT NULL,

    `день_недели` TINYINT UNSIGNED NOT NULL,

    `время_начала` TIME NOT NULL,
    `время_окончания` TIME NOT NULL,

    `доступен` BOOLEAN NOT NULL DEFAULT TRUE,

    PRIMARY KEY (`id`),

    KEY `idx_доступность_преподавателя`
        (`преподаватель_id`, `день_недели`),

    CONSTRAINT `fk_доступность_преподавателя`
        FOREIGN KEY (`преподаватель_id`)
        REFERENCES `преподаватель` (`id`)
        ON DELETE CASCADE
        ON UPDATE CASCADE,

    CONSTRAINT `chk_доступность_преподавателя_день`
        CHECK (`день_недели` BETWEEN 1 AND 7),

    CONSTRAINT `chk_доступность_преподавателя_время`
        CHECK (`время_начала` < `время_окончания`)
) ENGINE=InnoDB;


-- ============================================================
-- 12. ДОСТУПНОСТЬ АУДИТОРИЙ
-- ============================================================

CREATE TABLE `доступность_аудитории` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `аудитория_id` BIGINT UNSIGNED NOT NULL,

    `день_недели` TINYINT UNSIGNED NOT NULL,

    `время_начала` TIME NOT NULL,
    `время_окончания` TIME NOT NULL,

    `доступна` BOOLEAN NOT NULL DEFAULT TRUE,

    PRIMARY KEY (`id`),

    KEY `idx_доступность_аудитории`
        (`аудитория_id`, `день_недели`),

    CONSTRAINT `fk_доступность_аудитории`
        FOREIGN KEY (`аудитория_id`)
        REFERENCES `аудитория` (`id`)
        ON DELETE CASCADE
        ON UPDATE CASCADE,

    CONSTRAINT `chk_доступность_аудитории_день`
        CHECK (`день_недели` BETWEEN 1 AND 7),

    CONSTRAINT `chk_доступность_аудитории_время`
        CHECK (`время_начала` < `время_окончания`)
) ENGINE=InnoDB;


-- ============================================================
-- 13. РАСПИСАНИЕ
-- ============================================================

CREATE TABLE `расписание` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `семестр_id` BIGINT UNSIGNED NOT NULL,

    `дисциплина_id` BIGINT UNSIGNED NOT NULL,

    `преподаватель_id` BIGINT UNSIGNED NOT NULL,

    `группа_id` BIGINT UNSIGNED NOT NULL,

    `подгруппа_id` BIGINT UNSIGNED NULL,

    `аудитория_id` BIGINT UNSIGNED NOT NULL,

    `временной_слот_id` BIGINT UNSIGNED NOT NULL,

    `тип_занятия` ENUM(
        'лекция',
        'практика',
        'лабораторная',
        'семинар',
        'экзамен',
        'зачёт'
    ) NOT NULL,

    `тип_недели` ENUM(
        'каждая',
        'чётная',
        'нечётная'
    ) NOT NULL DEFAULT 'каждая',

    `дата_создания` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,

    PRIMARY KEY (`id`),

    KEY `idx_расписание_семестр`
        (`семестр_id`),

    KEY `idx_расписание_дисциплина`
        (`дисциплина_id`),

    KEY `idx_расписание_преподаватель`
        (`преподаватель_id`),

    KEY `idx_расписание_группа`
        (`группа_id`),

    KEY `idx_расписание_подгруппа`
        (`подгруппа_id`),

    KEY `idx_расписание_аудитория`
        (`аудитория_id`),

    KEY `idx_расписание_слот`
        (`временной_слот_id`),

    CONSTRAINT `fk_расписание_семестр`
        FOREIGN KEY (`семестр_id`)
        REFERENCES `семестр` (`id`)
        ON DELETE CASCADE
        ON UPDATE CASCADE,

    CONSTRAINT `fk_расписание_дисциплина`
        FOREIGN KEY (`дисциплина_id`)
        REFERENCES `дисциплина` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE,

    CONSTRAINT `fk_расписание_преподаватель`
        FOREIGN KEY (`преподаватель_id`)
        REFERENCES `преподаватель` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE,

    CONSTRAINT `fk_расписание_группа`
        FOREIGN KEY (`группа_id`)
        REFERENCES `группа` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE,

    CONSTRAINT `fk_расписание_подгруппа`
        FOREIGN KEY (`подгруппа_id`)
        REFERENCES `подгруппа` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE,

    CONSTRAINT `fk_расписание_аудитория`
        FOREIGN KEY (`аудитория_id`)
        REFERENCES `аудитория` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE,

    CONSTRAINT `fk_расписание_слот`
        FOREIGN KEY (`временной_слот_id`)
        REFERENCES `временной_слот` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE
) ENGINE=InnoDB;


-- ============================================================
-- 14. ЗАМЕНЫ ЗАНЯТИЙ
-- ============================================================

CREATE TABLE `замена_занятия` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `расписание_id` BIGINT UNSIGNED NOT NULL,

    `старая_дата` DATE NOT NULL,
    `новая_дата` DATE NULL,

    `старый_преподаватель_id` BIGINT UNSIGNED NULL,
    `новый_преподаватель_id` BIGINT UNSIGNED NULL,

    `старая_аудитория_id` BIGINT UNSIGNED NULL,
    `новая_аудитория_id` BIGINT UNSIGNED NULL,

    `причина` TEXT NULL,

    PRIMARY KEY (`id`),

    KEY `idx_замена_расписание`
        (`расписание_id`),

    CONSTRAINT `fk_замена_расписание`
        FOREIGN KEY (`расписание_id`)
        REFERENCES `расписание` (`id`)
        ON DELETE CASCADE
        ON UPDATE CASCADE,

    CONSTRAINT `fk_замена_старый_преподаватель`
        FOREIGN KEY (`старый_преподаватель_id`)
        REFERENCES `преподаватель` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE,

    CONSTRAINT `fk_замена_новый_преподаватель`
        FOREIGN KEY (`новый_преподаватель_id`)
        REFERENCES `преподаватель` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE,

    CONSTRAINT `fk_замена_старая_аудитория`
        FOREIGN KEY (`старая_аудитория_id`)
        REFERENCES `аудитория` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE,

    CONSTRAINT `fk_замена_новая_аудитория`
        FOREIGN KEY (`новая_аудитория_id`)
        REFERENCES `аудитория` (`id`)
        ON DELETE RESTRICT
        ON UPDATE CASCADE
) ENGINE=InnoDB;


-- ============================================================
-- 15. ОГРАНИЧЕНИЯ РАСПИСАНИЯ
-- ============================================================

CREATE TABLE `ограничение_расписания` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

    `название` VARCHAR(255) NOT NULL,

    `описание` TEXT NULL,

    `тип` VARCHAR(50) NOT NULL,

    `обязательное` BOOLEAN NOT NULL DEFAULT TRUE,

    `вес` INT UNSIGNED NOT NULL DEFAULT 1,

    PRIMARY KEY (`id`),

    CONSTRAINT `chk_ограничение_вес`
        CHECK (`вес` > 0)
) ENGINE=InnoDB;


-- ============================================================
-- 16. ЗАПОЛНЕНИЕ ВРЕМЕННЫХ СЛОТОВ
-- ============================================================

INSERT INTO `временной_слот`
(
    `номер_пары`,
    `день_недели`,
    `время_начала`,
    `время_окончания`
)
VALUES

-- ПОНЕДЕЛЬНИК
(1, 1, '08:30:00', '10:00:00'),
(2, 1, '10:10:00', '11:40:00'),
(3, 1, '11:50:00', '13:20:00'),
(4, 1, '13:50:00', '15:20:00'),
(5, 1, '15:30:00', '17:00:00'),
(6, 1, '17:10:00', '18:40:00'),

-- ВТОРНИК
(1, 2, '08:30:00', '10:00:00'),
(2, 2, '10:10:00', '11:40:00'),
(3, 2, '11:50:00', '13:20:00'),
(4, 2, '13:50:00', '15:20:00'),
(5, 2, '15:30:00', '17:00:00'),
(6, 2, '17:10:00', '18:40:00'),

-- СРЕДА
(1, 3, '08:30:00', '10:00:00'),
(2, 3, '10:10:00', '11:40:00'),
(3, 3, '11:50:00', '13:20:00'),
(4, 3, '13:50:00', '15:20:00'),
(5, 3, '15:30:00', '17:00:00'),
(6, 3, '17:10:00', '18:40:00'),

-- ЧЕТВЕРГ
(1, 4, '08:30:00', '10:00:00'),
(2, 4, '10:10:00', '11:40:00'),
(3, 4, '11:50:00', '13:20:00'),
(4, 4, '13:50:00', '15:20:00'),
(5, 4, '15:30:00', '17:00:00'),
(6, 4, '17:10:00', '18:40:00'),

-- ПЯТНИЦА
(1, 5, '08:30:00', '10:00:00'),
(2, 5, '10:10:00', '11:40:00'),
(3, 5, '11:50:00', '13:20:00'),
(4, 5, '13:50:00', '15:20:00'),
(5, 5, '15:30:00', '17:00:00'),
(6, 5, '17:10:00', '18:40:00'),

-- СУББОТА
(1, 6, '08:30:00', '10:00:00'),
(2, 6, '10:10:00', '11:40:00'),
(3, 6, '11:50:00', '13:20:00'),
(4, 6, '13:50:00', '15:20:00'),
(5, 6, '15:30:00', '17:00:00'),
(6, 6, '17:10:00', '18:40:00');


-- ============================================================
-- 17. БАЗОВЫЕ ОГРАНИЧЕНИЯ
-- ============================================================

INSERT INTO `ограничение_расписания`
(
    `название`,
    `описание`,
    `тип`,
    `обязательное`,
    `вес`
)
VALUES
(
    'Один преподаватель — одно занятие',
    'Преподаватель не может вести два занятия одновременно.',
    'преподаватель',
    TRUE,
    100
),
(
    'Одна группа — одно занятие',
    'Группа не может посещать два занятия одновременно.',
    'группа',
    TRUE,
    100
),
(
    'Одна аудитория — одно занятие',
    'Аудитория не может использоваться для двух занятий одновременно.',
    'аудитория',
    TRUE,
    100
),
(
    'Вместимость аудитории',
    'Количество студентов не должно превышать вместимость аудитории.',
    'вместимость',
    TRUE,
    100
),
(
    'Доступность преподавателя',
    'Занятие должно проходить в доступное время преподавателя.',
    'доступность_преподавателя',
    TRUE,
    90
),
(
    'Доступность аудитории',
    'Аудитория должна быть доступна в выбранное время.',
    'доступность_аудитории',
    TRUE,
    90
),
(
    'Соответствие типа аудитории',
    'Тип аудитории должен соответствовать типу занятия.',
    'тип_аудитории',
    TRUE,
    90
);


-- ============================================================
-- 18. ПРЕДСТАВЛЕНИЕ ПОЛНОГО РАСПИСАНИЯ
-- ============================================================

CREATE OR REPLACE VIEW `полное_расписание` AS

SELECT
    `р`.`id` AS `расписание_id`,

    `с`.`название` AS `семестр`,

    `г`.`название` AS `группа`,

    `пг`.`название` AS `подгруппа`,

    `д`.`код` AS `код_дисциплины`,

    `д`.`название` AS `дисциплина`,

    CONCAT_WS(
        ' ',
        `п`.`фамилия`,
        `п`.`имя`,
        `п`.`отчество`
    ) AS `преподаватель`,

    CONCAT(
        `а`.`корпус`,
        '-',
        `а`.`номер`
    ) AS `аудитория`,

    `вс`.`номер_пары`,

    CASE `вс`.`день_недели`
        WHEN 1 THEN 'Понедельник'
        WHEN 2 THEN 'Вторник'
        WHEN 3 THEN 'Среда'
        WHEN 4 THEN 'Четверг'
        WHEN 5 THEN 'Пятница'
        WHEN 6 THEN 'Суббота'
        WHEN 7 THEN 'Воскресенье'
    END AS `день`,

    `вс`.`время_начала`,
    `вс`.`время_окончания`,

    `р`.`тип_занятия`,
    `р`.`тип_недели`

FROM `расписание` AS `р`

INNER JOIN `семестр` AS `с`
    ON `с`.`id` = `р`.`семестр_id`

INNER JOIN `группа` AS `г`
    ON `г`.`id` = `р`.`группа_id`

LEFT JOIN `подгруппа` AS `пг`
    ON `пг`.`id` = `р`.`подгруппа_id`

INNER JOIN `дисциплина` AS `д`
    ON `д`.`id` = `р`.`дисциплина_id`

INNER JOIN `преподаватель` AS `п`
    ON `п`.`id` = `р`.`преподаватель_id`

INNER JOIN `аудитория` AS `а`
    ON `а`.`id` = `р`.`аудитория_id`

INNER JOIN `временной_слот` AS `вс`
    ON `вс`.`id` = `р`.`временной_слот_id`;


-- ============================================================
-- 19. ТРИГГЕР ПРОВЕРКИ КОНФЛИКТА ПРЕПОДАВАТЕЛЯ
-- ============================================================

DELIMITER $$

CREATE TRIGGER `проверка_конфликта_преподавателя`
BEFORE INSERT ON `расписание`
FOR EACH ROW
BEGIN

    IF EXISTS (
        SELECT 1
        FROM `расписание` AS `р`
        WHERE `р`.`семестр_id` = NEW.`семестр_id`
          AND `р`.`преподаватель_id` = NEW.`преподаватель_id`
          AND `р`.`временной_слот_id` = NEW.`временной_слот_id`
          AND (
                `р`.`тип_недели` = 'каждая'
                OR NEW.`тип_недели` = 'каждая'
                OR `р`.`тип_недели` = NEW.`тип_недели`
          )
    ) THEN

        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT =
            'Ошибка: преподаватель уже занят в выбранное время';

    END IF;

END$$


-- ============================================================
-- 20. ТРИГГЕР ПРОВЕРКИ КОНФЛИКТА ГРУППЫ
-- ============================================================

CREATE TRIGGER `проверка_конфликта_группы`
BEFORE INSERT ON `расписание`
FOR EACH ROW
BEGIN

    IF EXISTS (
        SELECT 1
        FROM `расписание` AS `р`
        WHERE `р`.`семестр_id` = NEW.`семестр_id`
          AND `р`.`группа_id` = NEW.`группа_id`
          AND `р`.`временной_слот_id` = NEW.`временной_слот_id`
          AND (
                `р`.`тип_недели` = 'каждая'
                OR NEW.`тип_недели` = 'каждая'
                OR `р`.`тип_недели` = NEW.`тип_недели`
          )
          AND (
                `р`.`подгруппа_id` IS NULL
                OR NEW.`подгруппа_id` IS NULL
                OR `р`.`подгруппа_id` = NEW.`подгруппа_id`
          )
    ) THEN

        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT =
            'Ошибка: группа уже занята в выбранное время';

    END IF;

END$$


-- ============================================================
-- 21. ТРИГГЕР ПРОВЕРКИ КОНФЛИКТА АУДИТОРИИ
-- ============================================================

CREATE TRIGGER `проверка_конфликта_аудитории`
BEFORE INSERT ON `расписание`
FOR EACH ROW
BEGIN

    IF EXISTS (
        SELECT 1
        FROM `расписание` AS `р`
        WHERE `р`.`семестр_id` = NEW.`семестр_id`
          AND `р`.`аудитория_id` = NEW.`аудитория_id`
          AND `р`.`временной_слот_id` = NEW.`временной_слот_id`
          AND (
                `р`.`тип_недели` = 'каждая'
                OR NEW.`тип_недели` = 'каждая'
                OR `р`.`тип_недели` = NEW.`тип_недели`
          )
    ) THEN

        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT =
            'Ошибка: аудитория уже занята в выбранное время';

    END IF;

END$$


-- ============================================================
-- 22. ТРИГГЕР ПРОВЕРКИ ВМЕСТИМОСТИ АУДИТОРИИ
-- ============================================================

CREATE TRIGGER `проверка_вместимости_аудитории`
BEFORE INSERT ON `расписание`
FOR EACH ROW
BEGIN

    DECLARE `количество_студентов` INT;
    DECLARE `вместимость_аудитории` INT;

    SELECT
        `количество_студентов`
    INTO
        `количество_студентов`
    FROM `группа`
    WHERE `id` = NEW.`группа_id`;


    SELECT
        `вместимость`
    INTO
        `вместимость_аудитории`
    FROM `аудитория`
    WHERE `id` = NEW.`аудитория_id`;


    IF `количество_студентов` > `вместимость_аудитории` THEN

        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT =
            'Ошибка: количество студентов превышает вместимость аудитории';

    END IF;

END$$


DELIMITER ;


-- ============================================================
-- 23. ПРОВЕРКА СОЗДАНИЯ БАЗЫ
-- ============================================================

SELECT
    'База данных учебного расписания успешно создана' AS `результат`;