Загрузка данных
-- ============================================================
-- БАЗА ДАННЫХ: УЧЕБНОЕ РАСПИСАНИЕ
-- СУБД: PostgreSQL
-- ============================================================
-- ============================================================
-- 1. СОЗДАНИЕ БАЗЫ ДАННЫХ
-- ============================================================
-- Выполняется отдельно, если база ещё не существует:
-- CREATE DATABASE "учебное_расписание";
-- После создания необходимо подключиться к базе
-- "учебное_расписание" и выполнить оставшуюся часть скрипта.
-- ============================================================
-- 2. ФАКУЛЬТЕТ
-- ============================================================
CREATE TABLE факультет (
id BIGSERIAL PRIMARY KEY,
название VARCHAR(200) NOT NULL UNIQUE
);
-- ============================================================
-- 3. ПРЕПОДАВАТЕЛЬ
-- ============================================================
CREATE TABLE преподаватель (
id BIGSERIAL PRIMARY KEY,
факультет_id BIGINT NOT NULL,
фамилия VARCHAR(100) NOT NULL,
имя VARCHAR(100) NOT NULL,
отчество VARCHAR(100),
email VARCHAR(255) UNIQUE,
CONSTRAINT fk_преподаватель_факультет
FOREIGN KEY (факультет_id)
REFERENCES факультет(id)
ON DELETE RESTRICT
);
-- ============================================================
-- 4. ДИСЦИПЛИНА
-- ============================================================
CREATE TABLE дисциплина (
id BIGSERIAL PRIMARY KEY,
код VARCHAR(50) NOT NULL UNIQUE,
название VARCHAR(255) NOT NULL,
тип VARCHAR(30) NOT NULL,
количество_часов INTEGER,
CONSTRAINT проверка_типа_дисциплины
CHECK (
тип IN (
'лекция',
'практика',
'лабораторная',
'семинар',
'экзамен',
'зачёт'
)
),
CONSTRAINT проверка_часов
CHECK (
количество_часов IS NULL
OR количество_часов > 0
)
);
-- ============================================================
-- 5. УЧЕБНАЯ ГРУППА
-- ============================================================
CREATE TABLE группа (
id BIGSERIAL PRIMARY KEY,
название VARCHAR(100) NOT NULL UNIQUE,
курс INTEGER NOT NULL,
количество_студентов INTEGER NOT NULL DEFAULT 0,
CONSTRAINT проверка_курса
CHECK (курс BETWEEN 1 AND 6),
CONSTRAINT проверка_количества_студентов
CHECK (количество_студентов >= 0)
);
-- ============================================================
-- 6. ПОДГРУППА
-- ============================================================
CREATE TABLE подгруппа (
id BIGSERIAL PRIMARY KEY,
группа_id BIGINT NOT NULL,
название VARCHAR(100) NOT NULL,
количество_студентов INTEGER,
CONSTRAINT fk_подгруппа_группа
FOREIGN KEY (группа_id)
REFERENCES группа(id)
ON DELETE CASCADE,
CONSTRAINT проверка_студентов_подгруппы
CHECK (
количество_студентов IS NULL
OR количество_студентов >= 0
),
CONSTRAINT уникальная_подгруппа
UNIQUE (группа_id, название)
);
-- ============================================================
-- 7. СВЯЗЬ ДИСЦИПЛИНЫ И ПРЕПОДАВАТЕЛЯ
-- ============================================================
CREATE TABLE дисциплина_преподаватель (
дисциплина_id BIGINT NOT NULL,
преподаватель_id BIGINT NOT NULL,
PRIMARY KEY (
дисциплина_id,
преподаватель_id
),
CONSTRAINT fk_дп_дисциплина
FOREIGN KEY (дисциплина_id)
REFERENCES дисциплина(id)
ON DELETE CASCADE,
CONSTRAINT fk_дп_преподаватель
FOREIGN KEY (преподаватель_id)
REFERENCES преподаватель(id)
ON DELETE CASCADE
);
-- ============================================================
-- 8. СВЯЗЬ ДИСЦИПЛИНЫ И ГРУППЫ
-- ============================================================
CREATE TABLE дисциплина_группа (
дисциплина_id BIGINT NOT NULL,
группа_id BIGINT NOT NULL,
PRIMARY KEY (
дисциплина_id,
группа_id
),
CONSTRAINT fk_дг_дисциплина
FOREIGN KEY (дисциплина_id)
REFERENCES дисциплина(id)
ON DELETE CASCADE,
CONSTRAINT fk_дг_группа
FOREIGN KEY (группа_id)
REFERENCES группа(id)
ON DELETE CASCADE
);
-- ============================================================
-- 9. АУДИТОРИЯ
-- ============================================================
CREATE TABLE аудитория (
id BIGSERIAL PRIMARY KEY,
корпус VARCHAR(100) NOT NULL,
номер VARCHAR(30) NOT NULL,
вместимость INTEGER NOT NULL,
тип VARCHAR(50) NOT NULL,
CONSTRAINT проверка_вместимости
CHECK (вместимость > 0),
CONSTRAINT уникальная_аудитория
UNIQUE (корпус, номер)
);
-- ============================================================
-- 10. СЕМЕСТР
-- ============================================================
CREATE TABLE семестр (
id BIGSERIAL PRIMARY KEY,
название VARCHAR(100) NOT NULL,
дата_начала DATE NOT NULL,
дата_окончания DATE NOT NULL,
CONSTRAINT проверка_дат_семестра
CHECK (дата_начала < дата_окончания)
);
-- ============================================================
-- 11. ВРЕМЕННОЙ СЛОТ
-- ============================================================
CREATE TABLE временной_слот (
id BIGSERIAL PRIMARY KEY,
номер_пары INTEGER NOT NULL,
день_недели INTEGER NOT NULL,
время_начала TIME NOT NULL,
время_окончания TIME NOT NULL,
CONSTRAINT проверка_номера_пары
CHECK (номер_пары > 0),
CONSTRAINT проверка_дня_недели
CHECK (день_недели BETWEEN 1 AND 7),
CONSTRAINT проверка_времени
CHECK (время_начала < время_окончания),
CONSTRAINT уникальный_временной_слот
UNIQUE (
день_недели,
номер_пары
)
);
-- ============================================================
-- 12. ДОСТУПНОСТЬ ПРЕПОДАВАТЕЛЯ
-- ============================================================
CREATE TABLE доступность_преподавателя (
id BIGSERIAL PRIMARY KEY,
преподаватель_id BIGINT NOT NULL,
день_недели INTEGER NOT NULL,
время_начала TIME NOT NULL,
время_окончания TIME NOT NULL,
доступен BOOLEAN NOT NULL DEFAULT TRUE,
CONSTRAINT fk_доступность_преподавателя
FOREIGN KEY (преподаватель_id)
REFERENCES преподаватель(id)
ON DELETE CASCADE,
CONSTRAINT проверка_дня_преподавателя
CHECK (день_недели BETWEEN 1 AND 7),
CONSTRAINT проверка_времени_преподавателя
CHECK (время_начала < время_окончания)
);
-- ============================================================
-- 13. ДОСТУПНОСТЬ АУДИТОРИИ
-- ============================================================
CREATE TABLE доступность_аудитории (
id BIGSERIAL PRIMARY KEY,
аудитория_id BIGINT NOT NULL,
день_недели INTEGER NOT NULL,
время_начала TIME NOT NULL,
время_окончания TIME NOT NULL,
доступна BOOLEAN NOT NULL DEFAULT TRUE,
CONSTRAINT fk_доступность_аудитории
FOREIGN KEY (аудитория_id)
REFERENCES аудитория(id)
ON DELETE CASCADE,
CONSTRAINT проверка_дня_аудитории
CHECK (день_недели BETWEEN 1 AND 7),
CONSTRAINT проверка_времени_аудитории
CHECK (время_начала < время_окончания)
);
-- ============================================================
-- 14. РАСПИСАНИЕ
-- ============================================================
CREATE TABLE расписание (
id BIGSERIAL PRIMARY KEY,
семестр_id BIGINT NOT NULL,
дисциплина_id BIGINT NOT NULL,
преподаватель_id BIGINT NOT NULL,
группа_id BIGINT NOT NULL,
подгруппа_id BIGINT,
аудитория_id BIGINT NOT NULL,
временной_слот_id BIGINT NOT NULL,
тип_занятия VARCHAR(30) NOT NULL,
тип_недели VARCHAR(20) NOT NULL DEFAULT 'каждая',
дата_создания TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_расписание_семестр
FOREIGN KEY (семестр_id)
REFERENCES семестр(id)
ON DELETE CASCADE,
CONSTRAINT fk_расписание_дисциплина
FOREIGN KEY (дисциплина_id)
REFERENCES дисциплина(id)
ON DELETE RESTRICT,
CONSTRAINT fk_расписание_преподаватель
FOREIGN KEY (преподаватель_id)
REFERENCES преподаватель(id)
ON DELETE RESTRICT,
CONSTRAINT fk_расписание_группа
FOREIGN KEY (группа_id)
REFERENCES группа(id)
ON DELETE RESTRICT,
CONSTRAINT fk_расписание_подгруппа
FOREIGN KEY (подгруппа_id)
REFERENCES подгруппа(id)
ON DELETE RESTRICT,
CONSTRAINT fk_расписание_аудитория
FOREIGN KEY (аудитория_id)
REFERENCES аудитория(id)
ON DELETE RESTRICT,
CONSTRAINT fk_расписание_слот
FOREIGN KEY (временной_слот_id)
REFERENCES временной_слот(id)
ON DELETE RESTRICT,
CONSTRAINT проверка_типа_занятия
CHECK (
тип_занятия IN (
'лекция',
'практика',
'лабораторная',
'семинар',
'экзамен',
'зачёт'
)
),
CONSTRAINT проверка_типа_недели
CHECK (
тип_недели IN (
'каждая',
'чётная',
'нечётная'
)
)
);
-- ============================================================
-- 15. ЗАМЕНЫ ЗАНЯТИЙ
-- ============================================================
CREATE TABLE замена_занятия (
id BIGSERIAL PRIMARY KEY,
расписание_id BIGINT NOT NULL,
старая_дата DATE NOT NULL,
новая_дата DATE,
старый_преподаватель_id BIGINT,
новый_преподаватель_id BIGINT,
старая_аудитория_id BIGINT,
новая_аудитория_id BIGINT,
причина TEXT,
CONSTRAINT fk_замена_расписание
FOREIGN KEY (расписание_id)
REFERENCES расписание(id)
ON DELETE CASCADE,
CONSTRAINT fk_замена_старый_преподаватель
FOREIGN KEY (старый_преподаватель_id)
REFERENCES преподаватель(id)
ON DELETE RESTRICT,
CONSTRAINT fk_замена_новый_преподаватель
FOREIGN KEY (новый_преподаватель_id)
REFERENCES преподаватель(id)
ON DELETE RESTRICT,
CONSTRAINT fk_замена_старая_аудитория
FOREIGN KEY (старая_аудитория_id)
REFERENCES аудитория(id)
ON DELETE RESTRICT,
CONSTRAINT fk_замена_новая_аудитория
FOREIGN KEY (новая_аудитория_id)
REFERENCES аудитория(id)
ON DELETE RESTRICT
);
-- ============================================================
-- 16. ОГРАНИЧЕНИЯ РАСПИСАНИЯ
-- ============================================================
CREATE TABLE ограничение_расписания (
id BIGSERIAL PRIMARY KEY,
название VARCHAR(255) NOT NULL,
описание TEXT,
тип VARCHAR(50) NOT NULL,
обязательное BOOLEAN NOT NULL DEFAULT TRUE,
вес INTEGER NOT NULL DEFAULT 1,
CONSTRAINT проверка_веса
CHECK (вес > 0)
);
-- ============================================================
-- 17. ИНДЕКСЫ
-- ============================================================
CREATE INDEX индекс_преподаватель_факультет
ON преподаватель(факультет_id);
CREATE INDEX индекс_подгруппа_группа
ON подгруппа(группа_id);
CREATE INDEX индекс_дисциплина_преподаватель_преподаватель
ON дисциплина_преподаватель(преподаватель_id);
CREATE INDEX индекс_дисциплина_группа_группа
ON дисциплина_группа(группа_id);
CREATE INDEX индекс_расписание_семестр
ON расписание(семестр_id);
CREATE INDEX индекс_расписание_дисциплина
ON расписание(дисциплина_id);
CREATE INDEX индекс_расписание_преподаватель
ON расписание(преподаватель_id);
CREATE INDEX индекс_расписание_группа
ON расписание(группа_id);
CREATE INDEX индекс_расписание_подгруппа
ON расписание(подгруппа_id);
CREATE INDEX индекс_расписание_аудитория
ON расписание(аудитория_id);
CREATE INDEX индекс_расписание_слот
ON расписание(временной_слот_id);
CREATE INDEX индекс_доступность_преподавателя
ON доступность_преподавателя(
преподаватель_id,
день_недели
);
CREATE INDEX индекс_доступность_аудитории
ON доступность_аудитории(
аудитория_id,
день_недели
);
-- ============================================================
-- 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 расписание р
JOIN семестр с
ON с.id = р.семестр_id
JOIN группа г
ON г.id = р.группа_id
LEFT JOIN подгруппа пг
ON пг.id = р.подгруппа_id
JOIN дисциплина д
ON д.id = р.дисциплина_id
JOIN преподаватель п
ON п.id = р.преподаватель_id
JOIN аудитория а
ON а.id = р.аудитория_id
JOIN временной_слот вс
ON вс.id = р.временной_слот_id;
-- ============================================================
-- 19. НАЧАЛЬНЫЕ ВРЕМЕННЫЕ СЛОТЫ
-- ============================================================
INSERT INTO временной_слот
(номер_пары, день_недели, время_начала, время_окончания)
VALUES
(1, 1, '08:30', '10:00'),
(2, 1, '10:10', '11:40'),
(3, 1, '11:50', '13:20'),
(4, 1, '13:50', '15:20'),
(5, 1, '15:30', '17:00'),
(6, 1, '17:10', '18:40'),
(1, 2, '08:30', '10:00'),
(2, 2, '10:10', '11:40'),
(3, 2, '11:50', '13:20'),
(4, 2, '13:50', '15:20'),
(5, 2, '15:30', '17:00'),
(6, 2, '17:10', '18:40'),
(1, 3, '08:30', '10:00'),
(2, 3, '10:10', '11:40'),
(3, 3, '11:50', '13:20'),
(4, 3, '13:50', '15:20'),
(5, 3, '15:30', '17:00'),
(6, 3, '17:10', '18:40'),
(1, 4, '08:30', '10:00'),
(2, 4, '10:10', '11:40'),
(3, 4, '11:50', '13:20'),
(4, 4, '13:50', '15:20'),
(5, 4, '15:30', '17:00'),
(6, 4, '17:10', '18:40'),
(1, 5, '08:30', '10:00'),
(2, 5, '10:10', '11:40'),
(3, 5, '11:50', '13:20'),
(4, 5, '13:50', '15:20'),
(5, 5, '15:30', '17:00'),
(6, 5, '17:10', '18:40'),
(1, 6, '08:30', '10:00'),
(2, 6, '10:10', '11:40'),
(3, 6, '11:50', '13:20'),
(4, 6, '13:50', '15:20'),
(5, 6, '15:30', '17:00'),
(6, 6, '17:10', '18:40');
-- ============================================================
-- 20. БАЗОВЫЕ ОГРАНИЧЕНИЯ
-- ============================================================
INSERT INTO ограничение_расписания
(название, описание, тип, обязательное, вес)
VALUES
(
'Один преподаватель — одно занятие',
'Преподаватель не может вести два занятия одновременно.',
'преподаватель',
TRUE,
100
),
(
'Одна группа — одно занятие',
'Группа не может посещать два занятия одновременно.',
'группа',
TRUE,
100
),
(
'Одна аудитория — одно занятие',
'Аудитория не может использоваться для двух занятий одновременно.',
'аудитория',
TRUE,
100
),
(
'Вместимость аудитории',
'Количество студентов не должно превышать вместимость аудитории.',
'вместимость',
TRUE,
100
),
(
'Доступность преподавателя',
'Занятие должно находиться в доступное для преподавателя время.',
'доступность_преподавателя',
TRUE,
90
),
(
'Доступность аудитории',
'Аудитория должна быть доступна в выбранное время.',
'доступность_аудитории',
TRUE,
90
),
(
'Лабораторная аудитория',
'Лабораторное занятие должно проходить в подходящей аудитории.',
'тип_аудитории',
TRUE,
90
);
-- ============================================================
-- КОНЕЦ СКРИПТА
-- ============================================================