- PVSM.RU - https://www.pvsm.ru -

Расчет нагрузки по кафедре

Решил поделится опытом решения частичной автоматизации документооборота на кафедре в ВУЗе. Это продолжение, в некотором смысле, моего поста Программа по составлению расписания занятий в ВУЗе [1]. Решение построено на бесплатных продуктах и успешно эксплуатируются в течение 6 лет.

Описание системы

Ниже представлено головное окно. С каждой кнопкой связанно редактирование или просмотр соответствующей таблицы БД или выполнение перерасчета часов и генерация отчетов. По функциональной зависимости кнопки расположены сналево права. Поэтому первая колонка и расположенная ниже всех строка с кнопками должности и преподаватели являются словарями.
Выделение строки с кнопками должности и преподаватели связанно и их редким использованием.
Расчет нагрузки по кафедре
Прокомментирую некоторые кнопки.

  • Наверно я неправильно называю дисциплины в ВУЗе предметами [2].
  • Разбиение это разбиение групп на подгруппы по проведению занятий (иностранный язык, лабораторные, компьютерные классы и т.д.).
  • Потоки представляют в моем контексте те уникальные названия групп, подгрупп и всевозможных потоков (всевозможных объединений из групп и подгрупп), которые мы видим в расписании занятий.

Ниже расположено окно для занесения и правки специальностей, а также бакалавров, магистров и чего только министерство образования не придумает.

Федеральное государственное бюджетное образовательное учреждение высшего профессионального образования далее название ВУЗа

Раз в 3-4 года у министерства, али еще у кого повыше, наступает обострение и оно себе меняет название, наверно думает, что становится умнее или креативние. А как следствие меняется официальное название ВУЗа. Вчера, например, была высказана очередная идиотская фраза [3] «Очевидно, что общее количество вузов превосходит все разумные рамки — Карфаген должен быть разрушен».

Расчет нагрузки по кафедре
Подгруппы для следущей формы плохое название, но я лучше не придумал. Подгруппы представляют собой соединение двух потоков по разбиению. Поток представляющий собой группы по специальности «прикладная математика» имеет надпоток по лекционному разбиению по всем группам «прикладной математики» для чтения лекций.
Расчет нагрузки по кафедре
Для удобства работы встроенны всевозможные фильтры, расположенные справа в форме. В данном окне включен фильтр по дневному отделению и по специальности «прикладная информатика».
Расчет нагрузки по кафедре
Заявки это то, что спускает деканат на кафедру в качестве учебных поручений. Например провести занятия на таком-то потоке по дисциплине «Базы данных». Это значит это часы за лекции и практику + расчетные часы за проведение текущих консультаций, проверку контрольных работ, консультаций перед экзаменом, прием экзамена или теоретического зачета и т.д. Последние часы зависят от количества студентов, правил расчета конкретного ВУЗа и текущего года. В моем Вузе их раз в пару лет меняют. Для их пересчета на первом рисунке служит кнопка «Обновить».

Еще немного пару спущу

Министерство требует от ВУЗа выполнение соотношения 1 преподователь = 10 студентов. Со следующего года будет так называемое по душевое финансирование. Т.е. у тебя не смогли сдать 10 студентов сессию, значит одну ставку преподавателя нужно сократить с факультета. При этом нагрузка преподавателя не должна превышать 900 часов, а на вопрос как она связанна с числом студентов ответ ректората никак. Такой же ответ я лично слышал и от более вышестоящих чиновников. Ты нагрузку то веди, а если нам надо будем мы тебя совершено за другое сократим.

Расчет нагрузки по кафедре
Следующее окно по выбранной заявке позволяет привязать нагрузку к конкретным преподавателям.
Расчет нагрузки по кафедре
Я не стал подробно показывать скриншоты для следующих кнопок с первого рисунка:

  • ЗаявкиРуков — курсовые и дипломные
  • НагрузкиРуков — расстановка преподавателей по курсовым и дипломным
  • НагрузкиДоп — руководство аспирантами, участие в ГЭКах и ГАКах, руководство практикой и т.д. Вся эта нагрузка считается по очень запутанным правилам и поэтому ее проще вбить и ее достаточно мало.
  • Кафедра — показывает как в текущий момент распределены часы по преподавателям и сколько часов еще осталось распределить

Основное целью здесь является генерация «Расчета часов», «Карточек учебных поручений» и других всевозможных бумаг. Они ниже представлены на трех скриншотах. Генерация делается в формате OpenDocument (ГОСТ Р ИСО/МЭК 26300-2010. Госстандарт России [4]) с полным форматированием и подстановкой готовых формул для суммирования по колонкам и строкам.
Расчет нагрузки по кафедре
Расчет нагрузки по кафедре
Расчет нагрузки по кафедре

Технические детали

Буду краток.

  • СУБД PosgreSQL.
  • GUI на PyQt.
  • Перерасчет часов (кнопка «Обновить») на Python.
  • Генерация отчетов посредством ODFPY [5].

Структура таблиц

Построена автоматически этой программой Автоматическое построение диаграмм сущность-связь [6] после небольшой модификации.
Расчет нагрузки по кафедре

SQL код

Мне очень не нравится мое решение с потоками, группами и подгруппами. В настоящее время у меня есть красивое решение [7] через наследование таблиц и рекурсивные запросы.
По поводу русских названий и префиксов tbl, vw, pk_, fk_ я предлагаю здесь не обсуждать. Я специально напишу про топик.

CREATE TABLE tblФормыОбучения (
  pk_ФормаОбучения SERIAL PRIMARY KEY,
  мнемо            TEXT UNIQUE,
  название         TEXT UNIQUE,
  примечание       TEXT
);

CREATE VIEW vwФормыОбучения AS
SELECT
  pk_ФормаОбучения,
  мнемо
FROM
  tblФормыОбучения
ORDER BY
  мнемо;

CREATE TABLE tblСпециальности (
  pk_Специальность SERIAL PRIMARY KEY,
  номер            TEXT,
  мнемо            TEXT UNIQUE,
  название         TEXT UNIQUE,
  примечание       TEXT
);

CREATE VIEW vwСпециальности AS
SELECT
  pk_Специальность,
  мнемо
FROM
  tblСпециальности
ORDER BY
  мнемо;

CREATE TABLE tblФакультеты (
  pk_Факультет     SERIAL PRIMARY KEY,
  мнемо            TEXT UNIQUE,
  название         TEXT UNIQUE,
  примечание       TEXT
);

CREATE VIEW vwФакультеты AS
SELECT
  pk_Факультет,
  мнемо
FROM
  tblФакультеты
ORDER BY
  мнемо;

CREATE TABLE tblПредметы (
  pk_Предмет  SERIAL PRIMARY KEY,
  название    TEXT UNIQUE
);

CREATE VIEW vwПредметы AS
SELECT
  pk_Предмет,
  название
FROM
  tblПредметы
ORDER BY
  название;

CREATE TABLE tblДолжности (
  pk_Должность     SERIAL PRIMARY KEY,
  название         TEXT UNIQUE
);

CREATE VIEW vwДолжности AS
SELECT
  pk_Должность,
  мнемо
FROM
  tblДолжности
ORDER BY
  мнемо;

CREATE TABLE tblПреподаватели (
  pk_Преподаватель SERIAL PRIMARY KEY,
  фамилия          TEXT,
  имя              TEXT,
  отчество         TEXT,
  fk_Должность     INTEGER REFERENCES tblДолжности(pk_Должность),
  ставка           TEXT,
  примечание       TEXT,
  UNIQUE(фамилия, имя, отчество)
);

CREATE VIEW vwПреподаватели AS
SELECT
  pk_Преподаватель,
  фамилия
FROM
  tblПреподаватели
ORDER BY
  фамилия;

CREATE TABLE tblРазбиения (
  pk_Разбиение SERIAL PRIMARY KEY,
  название     TEXT UNIQUE,
  примечание   TEXT
);

CREATE VIEW vwРазбиения AS
SELECT
  pk_Разбиение,
  название
FROM
  tblРазбиения
ORDER BY
  название;

CREATE TABLE tblПотоки (
  pk_Поток         SERIAL PRIMARY KEY,
  название         TEXT UNIQUE,
  UNIQUE(название)
);

CREATE VIEW vwПотоки AS
SELECT
  pk_Поток,
  название
FROM
  tblПотоки
ORDER BY
  название;

CREATE TABLE tblПодгруппы (
  pk_Подгруппа     SERIAL PRIMARY KEY,
  fk_Факультет     INTEGER REFERENCES tblФакультеты(pk_Факультет),
  fk_ФормаОбучения INTEGER REFERENCES tblФормыОбучения(pk_ФормаОбучения),
  fk_Специальность INTEGER REFERENCES tblСпециальности(pk_Специальность),
  fk_Разбиение     INTEGER REFERENCES tblРазбиения(pk_Разбиение),
  fk_НадПоток      INTEGER REFERENCES tblПотоки(pk_Поток),
  fk_Поток         INTEGER REFERENCES tblПотоки(pk_Поток),
  курс             INTEGER,
  комм             BOOLEAN,
  колБюджет        INTEGER,
  колКомм          INTEGER,
  примечание       TEXT,
  UNIQUE(fk_Разбиение, fk_НадПоток, fk_Поток)
);

CREATE VIEW vwПодгруппы AS
SELECT
  tblПодгруппы.pk_Подгруппа,
  tblПодгруппы.fk_Факультет,
  tblПодгруппы.fk_ФормаОбучения,
  tblПодгруппы.fk_Специальность,
  SUM(
    CASE
      WHEN tblПодгруппы1.fk_Разбиение = 4 AND NOT tblПодгруппы1.комм THEN
        1
      ELSE
        0
    END) AS лекБюджет,
  SUM(
    CASE
      WHEN tblПодгруппы1.fk_Разбиение = 4 AND tblПодгруппы1.комм THEN
        1
      ELSE
        0
    END) AS лекКомм,
  SUM(
    CASE
      WHEN tblПодгруппы1.fk_Разбиение = 1 AND NOT tblПодгруппы1.комм THEN
        1
      ELSE
        0
    END) AS семБюджет,
  SUM(
    CASE
      WHEN tblПодгруппы1.fk_Разбиение = 1 AND tblПодгруппы1.комм THEN
        1
      ELSE
        0
    END) AS семКомм,
  SUM(
    CASE
      WHEN tblПодгруппы1.fk_Разбиение = 2 AND NOT tblПодгруппы1.комм THEN
        1
      ELSE
        0
    END) AS лабБюджет,
  SUM(
    CASE
      WHEN tblПодгруппы1.fk_Разбиение = 2 AND tblПодгруппы1.комм THEN
        1
      ELSE
        0
    END) AS лабКомм,
  tblПодгруппы.fk_Поток,
  tblПодгруппы.курс,
  tblПодгруппы.комм,
  tblПодгруппы.колБюджет,
  tblПодгруппы.колКомм
FROM
  tblПодгруппы
    LEFT JOIN tblПодгруппы AS tblПодгруппы1 ON tblПодгруппы.fk_Поток = tblПодгруппы1.fk_НадПоток
WHERE
  tblПодгруппы.fk_Поток = tblПодгруппы.fk_НадПоток
GROUP BY
  tblПодгруппы.pk_Подгруппа,
  tblПодгруппы.fk_Факультет,
  tblПодгруппы.fk_ФормаОбучения,
  tblПодгруппы.fk_Специальность,
  tblПодгруппы.fk_Поток,
  tblПодгруппы.курс,
  tblПодгруппы.комм,
  tblПодгруппы.колБюджет,
  tblПодгруппы.колКомм;

CREATE TABLE tblЗаявки (
  pk_Заявка      SERIAL PRIMARY KEY,
  fk_Предмет     INTEGER REFERENCES tblПредметы(pk_Предмет),
  fk_Поток       INTEGER REFERENCES tblПотоки(pk_Поток),
  семестр        BOOLEAN,
  лек            INTEGER,
  сем            INTEGER,
  лаб            INTEGER,
  КСР            INTEGER,
  "т/конс"       BOOLEAN,
  экз            BOOLEAN,
  зач            BOOLEAN,
  "п/зач"        BOOLEAN,
  контр          BOOLEAN,
  CHECK(NOT(экз AND зач))
);

CREATE VIEW vw_fk_Заявки AS
SELECT
  pk_Заявка AS fk_Заявка,
  (CASE
    WHEN tblЗаявки.семестр THEN
      '1 '
    ELSE
      '2 '
  END) || tblПредметы.название AS мнемо
FROM
  tblЗаявки INNER JOIN tblПредметы
    ON tblЗаявки.fk_Предмет = tblПредметы.pk_Предмет
ORDER BY
  мнемо;

CREATE TABLE tblНагрузки (
  fk_Заявка         INTEGER REFERENCES tblЗаявки(pk_Заявка),
  fk_Поток          INTEGER REFERENCES tblПотоки(pk_Поток),
  комм              BOOLEAN,
  лекцонная         BOOLEAN,
  лек               INTEGER,
  сем               INTEGER,
  лаб               INTEGER,
  КСР               INTEGER,
  "т/конс"          REAL,
  "э/конс"          REAL,
  экз               REAL,
  зач               REAL,
  контр             REAL,
  fk_Преподаватель  INTEGER REFERENCES tblПреподаватели(pk_Преподаватель),
  PRIMARY KEY(fk_Заявка, fk_Поток, лекцонная, комм),
  CHECK(NOT(экз > 0.0 AND зач > 0.0))
);

CREATE VIEW vwНагрузки AS
SELECT
  pk_Заявка,
  tblФакультеты.мнемо AS Факультет,
  tblФормыОбучения.мнемо AS ФормаОбучения,
  tblСпециальности.мнемо AS спец,
  курс,
  tblПотоки.название AS поток,
  (CASE
    WHEN tblНагрузки.комм THEN
      колКомм
    ELSE
      колБюджет
  END) AS студентов,
  tblПредметы.название AS предмет,
  (CASE
    WHEN семестр THEN
      1
    ELSE
      2
  END) AS семестр,
  SUM(tblНагрузки.лек) AS лек,
  SUM(tblНагрузки.сем) AS сем,
  SUM(tblНагрузки.лаб) AS лаб,
  SUM(tblНагрузки."т/конс") AS "т/конс",
  SUM(tblНагрузки."э/конс") AS "э/конс",
  SUM(tblНагрузки.экз) AS экз,
  SUM(tblНагрузки.зач) AS зач,
  SUM(tblНагрузки.контр) AS контр,
  tblНагрузки.комм AS комм,
  tblПреподаватели.фамилия AS препод
FROM
  tblЗаявки
    LEFT JOIN tblНагрузки ON tblЗаявки.pk_Заявка = tblНагрузки.fk_Заявка
    LEFT JOIN vwПодгруппы ON tblЗаявки.fk_Поток = vwПодгруппы.fk_Поток
    LEFT JOIN tblФакультеты ON vwПодгруппы.fk_Факультет = tblФакультеты.pk_Факультет
    LEFT JOIN tblФормыОбучения ON vwПодгруппы.fk_ФормаОбучения = tblФормыОбучения.pk_ФормаОбучения
    LEFT JOIN tblСпециальности ON vwПодгруппы.fk_Специальность = tblСпециальности.pk_Специальность
    LEFT JOIN tblПредметы ON tblЗаявки.fk_Предмет = tblПредметы.pk_Предмет
    LEFT JOIN tblПотоки ON tblЗаявки.fk_Поток = tblПотоки.pk_Поток
    LEFT JOIN tblПреподаватели ON tblНагрузки.fk_Преподаватель = tblПреподаватели.pk_Преподаватель
GROUP BY
  pk_Заявка,
  tblФакультеты.мнемо,
  tblФормыОбучения.мнемо,
  tblСпециальности.мнемо,
  tblПотоки.название,
  курс,
  студентов,
  tblПредметы.название,
  семестр,
  tblНагрузки.комм,
  tblПреподаватели.фамилия
ORDER BY
  Факультет,
  ФормаОбучения,
  спец,
  курс,
  поток,
  предмет,
  семестр;

CREATE TABLE tblЗаявкиРуков (
  pk_ЗаявкаРуков  SERIAL PRIMARY KEY,
  fk_Предмет      INTEGER REFERENCES tblПредметы(pk_Предмет),
  fk_Поток        INTEGER REFERENCES tblПотоки(pk_Поток),
  семестр         BOOLEAN,
  "курс/раб"      BOOLEAN,
  "дип/бак"       BOOLEAN
);

CREATE VIEW vw_fk_ЗаявкиРуков AS
SELECT
  pk_ЗаявкаРуков AS fk_ЗаявкаРуков,
  (CASE
    WHEN tblЗаявкиРуков.семестр THEN
      '1 '
    ELSE
      '2 '
  END) || tblПредметы.название AS мнемо
FROM
  tblЗаявкиРуков INNER JOIN tblПредметы
    ON tblЗаявкиРуков.fk_Предмет = tblПредметы.pk_Предмет
ORDER BY
  мнемо;

CREATE TABLE tblНагрузкиРуков (
  fk_ЗаявкаРуков    INTEGER REFERENCES tblЗаявкиРуков(pk_ЗаявкаРуков),
--   fk_Поток          INTEGER REFERENCES tblПотоки(pk_Поток),
  комм              BOOLEAN,
  номер             INTEGER,
  часов             INTEGER,
  студент           TEXT,
  тема              TEXT,
  fk_Преподаватель  INTEGER REFERENCES tblПреподаватели(pk_Преподаватель),
  PRIMARY KEY(fk_ЗаявкаРуков, комм, номер)
);

CREATE VIEW vwНагрузкиРуков AS
SELECT
  pk_ЗаявкаРуков,
  tblФакультеты.мнемо AS Факультет,
  tblФормыОбучения.мнемо AS ФормаОбучения,
  tblСпециальности.мнемо AS спец,
  курс,
  tblПотоки.название AS поток,
  COUNT(*) AS студентов,
  tblПредметы.название AS предмет,
  (CASE
    WHEN семестр THEN
      1
    ELSE
      2
  END) AS семестр,
  (CASE
    WHEN "курс/раб" THEN
      SUM(tblНагрузкиРуков.часов)
    ELSE
      0
  END) AS курсов,
  (CASE
    WHEN "дип/бак" THEN
      SUM(tblНагрузкиРуков.часов)
    ELSE
      0
  END) AS димпл,
  tblНагрузкиРуков.комм AS комм,
  tblПреподаватели.фамилия AS препод
FROM
  tblЗаявкиРуков
    LEFT JOIN tblНагрузкиРуков ON tblЗаявкиРуков.pk_ЗаявкаРуков = tblНагрузкиРуков.fk_ЗаявкаРуков
    LEFT JOIN vwПодгруппы ON tblЗаявкиРуков.fk_Поток = vwПодгруппы.fk_Поток
    LEFT JOIN tblФакультеты ON vwПодгруппы.fk_Факультет = tblФакультеты.pk_Факультет
    LEFT JOIN tblФормыОбучения ON vwПодгруппы.fk_ФормаОбучения = tblФормыОбучения.pk_ФормаОбучения
    LEFT JOIN tblСпециальности ON vwПодгруппы.fk_Специальность = tblСпециальности.pk_Специальность
    LEFT JOIN tblПредметы ON tblЗаявкиРуков.fk_Предмет = tblПредметы.pk_Предмет
    LEFT JOIN tblПотоки ON tblЗаявкиРуков.fk_Поток = tblПотоки.pk_Поток
    LEFT JOIN tblПреподаватели ON tblНагрузкиРуков.fk_Преподаватель = tblПреподаватели.pk_Преподаватель
GROUP BY
  pk_ЗаявкаРуков,
  tblФакультеты.мнемо,
  tblФормыОбучения.мнемо,
  tblСпециальности.мнемо,
  tblПотоки.название,
  курс,
  tblПредметы.название,
  семестр,
  "курс/раб",
  "дип/бак",
  tblНагрузкиРуков.комм,
  tblПреподаватели.фамилия
ORDER BY
  Факультет,
  ФормаОбучения,
  спец,
  курс,
  поток,
  предмет,
  семестр;

CREATE TABLE tblНагрузкиДоп (
  pk_НагрузкаДоп    SERIAL PRIMARY KEY,
  fk_Поток          INTEGER REFERENCES tblПотоки(pk_Поток),
  семестр           BOOLEAN,
  практ             REAL,
  ГЭК               REAL,
  ГАК               REAL,
  прием             INTEGER,
  курат             INTEGER,
  "каф/рук"         INTEGER,
  "асп/рук"         INTEGER,
  факул             INTEGER,
  комм              BOOLEAN,
  fk_Преподаватель  INTEGER REFERENCES tblПреподаватели(pk_Преподаватель)
);

CREATE VIEW vwНагрузкиДоп AS
SELECT
  pk_НагрузкаДоп,
  (CASE
    WHEN tblФакультеты.мнемо IS NULL THEN
      'м/м'
    ELSE
      tblФакультеты.мнемо
  END) AS Факультет,
  (CASE
    WHEN tblФормыОбучения.мнемо IS NULL THEN
      'д/о'
    ELSE
      tblФормыОбучения.мнемо
  END) AS ФормаОбучения,
  tblСпециальности.мнемо AS спец,
  курс,
  tblПотоки.название AS поток,
  (CASE
    WHEN tblНагрузкиДоп.комм THEN
      колКомм
    ELSE
      колБюджет
  END) AS студентов,
  (CASE
    WHEN семестр THEN
      1
    ELSE
      2
  END) AS семестр,
  практ,
  ГЭК+ГАК AS ГАК,
  "асп/рук",
  "каф/рук",
  факул,
  курат,
  прием,
  tblНагрузкиДоп.комм AS комм,
  tblПреподаватели.фамилия AS препод
FROM
  tblНагрузкиДоп
    LEFT JOIN vwПодгруппы ON tblНагрузкиДоп.fk_Поток = vwПодгруппы.fk_Поток
    LEFT JOIN tblФакультеты ON vwПодгруппы.fk_Факультет = tblФакультеты.pk_Факультет
    LEFT JOIN tblФормыОбучения ON vwПодгруппы.fk_ФормаОбучения = tblФормыОбучения.pk_ФормаОбучения
    LEFT JOIN tblСпециальности ON vwПодгруппы.fk_Специальность = tblСпециальности.pk_Специальность
    LEFT JOIN tblПотоки ON tblНагрузкиДоп.fk_Поток = tblПотоки.pk_Поток
    LEFT JOIN tblПреподаватели ON tblНагрузкиДоп.fk_Преподаватель = tblПреподаватели.pk_Преподаватель
ORDER BY
  Факультет,
  ФормаОбучения,
  спец,
  курс,
  поток,
  семестр;

CREATE VIEW vwКарточки AS
SELECT
  Факультет,
  ФормаОбучения,
  спец,
  курс,
  поток,
  студентов,
  предмет,
  семестр,
  SUM(лек) AS лек,
  SUM(сем) AS сем,
  SUM(лаб) AS лаб,
  SUM("т/конс") AS "т/конс",
  SUM("э/конс") AS "э/конс",
  SUM(экз) AS экз,
  SUM(зач) AS зач,
  SUM(практ) AS практ,
  SUM(курсов) AS курсов,
  SUM(димпл) AS димпл,
  SUM(ГАК) AS ГАК,
  SUM(контр) AS контр,
  SUM("асп/рук") AS "асп/рук",
  SUM("каф/рук") AS "каф/рук",
  SUM(факул) AS факул,
  SUM(курат) AS курат,
  SUM(прием) AS прием,
  комм,
  препод
FROM
(
(SELECT
  Факультет,
  ФормаОбучения,
  спец,
  курс,
  поток,
  студентов,
  предмет,
  семестр,
  лек,
  сем,
  лаб,
  "т/конс",
  "э/конс",
  экз,
  зач,
  0 AS практ,
  0 AS курсов,
  0 AS димпл,
  0 AS ГАК,
  контр,
  0 AS "асп/рук",
  0 AS "каф/рук",
  0 AS факул,
  0 AS курат,
  0 AS прием,
  комм,
  препод
FROM
  vwНагрузки)
UNION
(SELECT
  Факультет,
  ФормаОбучения,
  спец,
  курс,
  поток,
  студентов,
  предмет,
  семестр,
  0 AS лек,
  0 AS сем,
  0 AS лаб,
  0 AS "т/конс",
  0 AS "э/конс",
  0 AS экз,
  0 AS зач,
  0 AS практ,
  курсов,
  димпл,
  0 AS ГАК,
  0 AS контр,
  0 AS "асп/рук",
  0 AS "каф/рук",
  0 AS факул,
  0 AS курат,
  0 AS прием,
  комм,
  препод
FROM
  vwНагрузкиРуков)
UNION
(SELECT
  Факультет,
  ФормаОбучения,
  спец,
  курс,
  поток,
  студентов,
  '' AS предмет,
  семестр,
  0 AS лек,
  0 AS сем,
  0 AS лаб,
  0 AS "т/конс",
  0 AS "э/конс",
  0 AS экз,
  0 AS зач,
  практ,
  0 AS курсов,
  0 AS димпл,
  ГАК,
  0 AS контр,
  "асп/рук",
  "каф/рук",
  факул,
  курат,
  прием,
  комм,
  препод
FROM
  vwНагрузкиДоп)
) AS нагрука
GROUP BY
  Факультет,
  ФормаОбучения,
  спец,
  курс,
  поток,
  студентов,
  предмет,
  семестр,
  комм,
  препод
ORDER BY
  Факультет,
  ФормаОбучения,
  спец,
  курс,
  поток,
  предмет,
  семестр;

CREATE VIEW vwНагрузкаПрепод AS
SELECT
  комм,
  SUM(часов) AS часов,
  фамилия AS препод
FROM ((
(SELECT
  комм,
  SUM(лек + сем + лаб + "т/конс" + "э/конс" + экз + зач + контр) AS часов,
  fk_Преподаватель
FROM
  tblНагрузки
GROUP BY
  комм,
  fk_Преподаватель)
UNION
(SELECT
  комм,
  SUM(часов) AS часов,
  fk_Преподаватель
FROM
  tblНагрузкиРуков
GROUP BY
  комм,
  fk_Преподаватель)
UNION
(SELECT
  комм,
  SUM (практ + ГЭК + ГАК + прием + курат + "каф/рук" + "асп/рук" + факул) AS часов,
  fk_Преподаватель
FROM
  tblНагрузкиДоп
GROUP BY
  комм,
  fk_Преподаватель)
) AS нагрузка)
LEFT JOIN vwПреподаватели
    ON нагрузка.fk_Преподаватель = vwПреподаватели.pk_Преподаватель
GROUP BY
  комм,
  препод
ORDER BY
  препод,
  комм;

CREATE VIEW vwНагрузка AS
SELECT
  комм,
  SUM(часов) AS часов
FROM (
(SELECT
  комм,
  SUM(лек + сем + лаб + "т/конс" + "э/конс" + экз + зач + контр) AS часов
FROM
  tblНагрузки
GROUP BY
   комм)
UNION
(SELECT
  комм,
  SUM(часов) AS часов
FROM
  tblНагрузкиРуков
GROUP BY
   комм)
UNION
(SELECT
  комм,
  SUM(практ + ГЭК + ГАК + прием + курат + "каф/рук" + "асп/рук" + факул) AS часов
FROM
  tblНагрузкиДоп
GROUP BY
   комм)
) AS Нагрузка
GROUP BY
   комм;

-------------------------------------------------------------------------------------------
CREATE VIEW vwНагрузки1 AS
SELECT
  fk_Заявка,
  fk_Предмет,
  tblЗаявки.fk_Поток AS fk_ПотокЗаявка,
  tblНагрузки.fk_Поток AS fk_ПотокНагрузка,
  (CASE
    WHEN семестр THEN
      1
    ELSE
      2
  END) AS семестр,
  SUM(tblНагрузки.лек) AS лек,
  SUM(tblНагрузки.сем) AS сем,
  SUM(tblНагрузки.лаб) AS лаб,
  SUM(tblНагрузки."т/конс") AS "т/конс",
  SUM(tblНагрузки."э/конс") AS "э/конс",
  SUM(tblНагрузки.экз) AS экз,
  SUM(tblНагрузки.зач) AS зач,
  SUM(tblНагрузки.контр) AS контр,
  tblНагрузки.комм AS комм,
  fk_Преподаватель
FROM
  tblЗаявки
    LEFT JOIN tblНагрузки ON tblЗаявки.pk_Заявка = tblНагрузки.fk_Заявка
GROUP BY
  fk_Заявка,
  fk_Предмет,
  tblЗаявки.fk_Поток,
  tblНагрузки.fk_Поток,
  семестр,
  tblНагрузки.комм,
  fk_Преподаватель;

CREATE VIEW vwНагрузкиРуков1 AS
SELECT
  fk_ЗаявкаРуков,
  fk_Предмет,
  tblЗаявкиРуков.fk_Поток AS fk_Поток,
  (CASE
    WHEN семестр THEN
      1
    ELSE
      2
  END) AS семестр,
  COUNT(*) AS студентов,
  (CASE
    WHEN "курс/раб" THEN
      SUM(tblНагрузкиРуков.часов)
    ELSE
      0
  END) AS курсов,
  (CASE
    WHEN "дип/бак" THEN
      SUM(tblНагрузкиРуков.часов)
    ELSE
      0
  END) AS димпл,
  tblНагрузкиРуков.комм AS комм,
  fk_Преподаватель
FROM
  tblЗаявкиРуков
    LEFT JOIN tblНагрузкиРуков ON tblЗаявкиРуков.pk_ЗаявкаРуков = tblНагрузкиРуков.fk_ЗаявкаРуков
GROUP BY
  fk_ЗаявкаРуков,
  fk_Предмет,
  tblЗаявкиРуков.fk_Поток,
  семестр,
  "курс/раб",
  "дип/бак",
  tblНагрузкиРуков.комм,
  fk_Преподаватель;

CREATE VIEW vwНагрузкиДоп1 AS
SELECT
  pk_НагрузкаДоп AS fk_НагрузкаДоп,
  fk_Поток,
  (CASE
    WHEN семестр THEN
      1
    ELSE
      2
  END) AS семестр,
  практ,
  ГЭК+ГАК AS ГАК,
  "асп/рук",
  "каф/рук",
  факул,
  курат,
  прием,
  комм,
  fk_Преподаватель
FROM
  tblНагрузкиДоп;

CREATE VIEW vwКарточки1 AS
SELECT
  *
FROM
((
SELECT
  fk_Предмет,
  fk_ПотокЗаявка AS fk_Поток,
  CASE
    WHEN vwНагрузки1.комм THEN
      колКомм
    ELSE
      колБюджет
  END AS студентов,
  CASE
    WHEN vwНагрузки1.комм THEN
      лекКомм
    ELSE
      лекБюджет
  END AS лекГрупп,
  CASE
    WHEN vwНагрузки1.комм THEN
      семКомм
    ELSE
      семБюджет
  END AS семГрупп,
  CASE
    WHEN vwНагрузки1.комм THEN
      лабКомм
    ELSE
      лабБюджет
  END AS лабГрупп,
  семестр,
  SUM(vwНагрузки1.лек) AS лек,
  SUM(vwНагрузки1.сем) AS сем,
  SUM(vwНагрузки1.лаб) AS лаб,
  SUM(vwНагрузки1."т/конс") AS "т/конс",
  SUM(vwНагрузки1."э/конс") AS "э/конс",
  SUM(vwНагрузки1.экз) AS экз,
  SUM(vwНагрузки1.зач) AS зач,
  0 AS практ,
  0 AS курсов,
  0 AS димпл,
  0 AS ГАК,
  SUM(vwНагрузки1.контр) AS контр,
  0 AS "асп/рук",
  0 AS "каф/рук",
  0 AS факул,
  0 AS курат,
  0 AS прием,
  vwНагрузки1.комм AS комм,
  fk_Преподаватель
FROM
  vwНагрузки1
     LEFT JOIN vwПодгруппы ON vwНагрузки1.fk_ПотокЗаявка = vwПодгруппы.fk_Поток
GROUP BY
  vwНагрузки1.fk_ПотокЗаявка,
  fk_Предмет,
  студентов,
  лекГрупп,
  семГрупп,
  лабГрупп,
  семестр,
  vwНагрузки1.комм,
  fk_Преподаватель
) UNION (
SELECT
  fk_Предмет,
  fk_Поток,
  студентов,
  0 AS лекГрупп,
  0 AS семГрупп,
  0 AS лабГрупп,
  семестр,
  0 AS лек,
  0 AS сем,
  0 AS лаб,
  0 AS "т/конс",
  0 AS "э/конс",
  0 AS экз,
  0 AS зач,
  0 AS практ,
  курсов,
  димпл,
  0 AS ГАК,
  0 AS контр,
  0 AS "асп/рук",
  0 AS "каф/рук",
  0 AS факул,
  0 AS курат,
  0 AS прием,
  комм,
  fk_Преподаватель
FROM
  vwНагрузкиРуков1
) UNION (
SELECT
  NULL AS fk_Предмет,
  vwНагрузкиДоп1.fk_Поток AS fk_Поток,
  CASE
    WHEN vwНагрузкиДоп1.комм THEN
      колКомм
    ELSE
      колБюджет
  END AS студентов,
  0 AS лекГрупп,
  0 AS семГрупп,
  0 AS лабГрупп,
  семестр,
  0 AS лек,
  0 AS сем,
  0 AS лаб,
  0 AS "т/конс",
  0 AS "э/конс",
  0 AS экз,
  0 AS зач,
  практ,
  0 AS курсов,
  0 AS димпл,
  ГАК,
  0 AS контр,
  "асп/рук",
  "каф/рук",
  факул,
  курат,
  прием,
  vwНагрузкиДоп1.комм AS комм,
  fk_Преподаватель
FROM
  vwНагрузкиДоп1
    LEFT JOIN vwПодгруппы ON vwНагрузкиДоп1.fk_Поток = vwПодгруппы.fk_Поток
)) AS нагрука;

CREATE VIEW vwКарточки2 AS
SELECT
  *
FROM
((
SELECT
  fk_Предмет,
  fk_ПотокЗаявка AS fk_Поток,
  CASE
    WHEN vwНагрузки1.комм THEN
      колКомм
    ELSE
      колБюджет
  END AS студентов,
  CASE
    WHEN vwНагрузки1.комм THEN
      лекКомм
    ELSE
      лекБюджет
  END AS лекГрупп,
  CASE
    WHEN vwНагрузки1.комм THEN
      семКомм
    ELSE
      семБюджет
  END AS семГрупп,
  CASE
    WHEN vwНагрузки1.комм THEN
      лабКомм
    ELSE
      лабБюджет
  END AS лабГрупп,
  семестр,
  SUM(vwНагрузки1.лек) AS лек,
  SUM(vwНагрузки1.сем) AS сем,
  SUM(vwНагрузки1.лаб) AS лаб,
  SUM(vwНагрузки1."т/конс") AS "т/конс",
  SUM(vwНагрузки1."э/конс") AS "э/конс",
  SUM(vwНагрузки1.экз) AS экз,
  SUM(vwНагрузки1.зач) AS зач,
  0 AS практ,
  0 AS курсов,
  0 AS димпл,
  0 AS ГАК,
  SUM(vwНагрузки1.контр) AS контр,
  0 AS "асп/рук",
  0 AS "каф/рук",
  0 AS факул,
  0 AS курат,
  0 AS прием,
  vwНагрузки1.комм AS комм
FROM
  vwНагрузки1
     LEFT JOIN vwПодгруппы ON vwНагрузки1.fk_ПотокЗаявка = vwПодгруппы.fk_Поток
GROUP BY
  vwНагрузки1.fk_ПотокЗаявка,
  fk_Предмет,
  студентов,
  лекГрупп,
  семГрупп,
  лабГрупп,
  семестр,
  vwНагрузки1.комм
) UNION (
SELECT
  fk_Предмет,
  fk_Поток,
  SUM(студентов) AS студентов,
  0 AS лекГрупп,
  0 AS семГрупп,
  0 AS лабГрупп,
  семестр,
  0 AS лек,
  0 AS сем,
  0 AS лаб,
  0 AS "т/конс",
  0 AS "э/конс",
  0 AS экз,
  0 AS зач,
  0 AS практ,
  SUM(курсов) AS курсов,
  SUM(димпл) AS димпл,
  0 AS ГАК,
  0 AS контр,
  0 AS "асп/рук",
  0 AS "каф/рук",
  0 AS факул,
  0 AS курат,
  0 AS прием,
  комм
FROM
  vwНагрузкиРуков1
GROUP BY
  fk_Предмет,
  fk_Поток,
  семестр,
  комм
) UNION (
SELECT
  NULL AS fk_Предмет,
  vwНагрузкиДоп1.fk_Поток AS fk_Поток,
  CASE
    WHEN vwНагрузкиДоп1.комм THEN
      колКомм
    ELSE
      колБюджет
  END AS студентов,
  0 AS лекГрупп,
  0 AS семГрупп,
  0 AS лабГрупп,
  SUM(семестр),
  0 AS лек,
  0 AS сем,
  0 AS лаб,
  0 AS "т/конс",
  0 AS "э/конс",
  0 AS экз,
  0 AS зач,
  SUM(практ),
  0 AS курсов,
  0 AS димпл,
  SUM(ГАК),
  0 AS контр,
  "асп/рук",
  "каф/рук",
  SUM(факул),
  SUM(курат),
  SUM(прием),
  vwНагрузкиДоп1.комм AS комм
FROM
  vwНагрузкиДоп1
    LEFT JOIN vwПодгруппы ON vwНагрузкиДоп1.fk_Поток = vwПодгруппы.fk_Поток
GROUP BY
  fk_НагрузкаДоп,
  vwНагрузкиДоп1.fk_Поток,
  vwНагрузкиДоп1.комм,
  колКомм,
  колБюджет,
  семестр,
  "асп/рук",
  "каф/рук"
)) AS нагрука;

Заключение

Повторно [1] предлагаю следующие решение (набросок).

  • GUI на PyQt или PySide
  • СУБД PosgreSQL (у меня здесь готово примерно на 80%), в ней кроме самого расписания еще заявки и нагрузка преподавателей, учебные планы и еще много чего (с этой целью опубликую один или несколько топиков)
  • web интерфейс на CherryPy+Cheetah (но это может обсуждаться)
  • экспорт всяких отчетов (расписаний, карточек учебных поручений и т.д.) в формате OpenDocument (ГОСТ Р ИСО/МЭК 26300-2010. Госстандарт России (01.06.2011) [4]) посредством ODFPY [5]
  • алгоритмы составления расписания от меня (напишу об этом топик)
  • постановка от меня
  • для заинтересованных работа над общим ядром
  • для заинтересованных адаптация под собственный ВУЗ и возможность гибко все менять, жизнь идет, а чиновники не дремлют

Спасибо Всем кто откликнулся, после публикации топика по алгоритмам составления расписания можно будет со организоваться.

Автор: bya


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/python/12074

Ссылки в тексте:

[1] Программа по составлению расписания занятий в ВУЗе: http://habrahabr.ru/post/147997/

[2] предметами: http://habrahabr.ru/post/147997/#comment_4997148

[3] очередная идиотская фраза: http://lenta.ru/news/2012/07/25/carthage/

[4] ГОСТ Р ИСО/МЭК 26300-2010. Госстандарт России: http://ru.wikipedia.org/wiki/OpenDocument

[5] ODFPY: http://opendocumentfellowship.com/projects/odfpy

[6] Автоматическое построение диаграмм сущность-связь: http://habrahabr.ru/post/147349/

[7] красивое решение: http://habrahabr.ru/post/148258/#comment_5004234