Идея
Представьте себе образовательный центр с отраслями. Курсы этого образовательного центра являются общими для всех веток.
Филиалы
CREATE TABLE `Branch` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
CREATE TABLE `Course` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`active` tinyint(1) DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
Номера в каждой ветке для каждого курса, созданного администраторами. Например, администратор вводит количество комнат для курса Math. Система генерирует 3 комнаты. Другими словами, они ограничены подсчетом.
CREATE TABLE `Room` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`branch_id` int(10) unsigned DEFAULT NULL,
`course_id` int(10) unsigned DEFAULT NULL,
`occupied_hours` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
В каждом номере есть 5 доступных часов обучения в день. Другими словами, Math-1
будет иметь одну группу студентов в каждый учебный час (5).
Студенты, также сгруппированные по веткам. Каждый студент предложил еженедельный план (week_day_mode
), чтобы поступить в среднюю школу.
- за 1, 3, 5 дней недели.
- в течение 2, 4, 6 дней недели.
class
- класс в школе (основная школа),
CREATE TABLE `Student` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`fullname` varchar(255) NOT NULL,
`class` tinyint(2) DEFAULT NULL,
`branchID` int(10) unsigned DEFAULT NULL,
`week_day_mode` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `branchID` (`branchID`)
) ENGINE=InnoDB AUTO_INCREMENT=246 DEFAULT CHARSET=utf8;
Когда администратор регистрирует учащегося в первый раз, он выбирает все курсы, которые хочет принять учащийся. Например, если 5 выбранных курсов StudentCourseAssoc
будут заполнены 5 строками для этого ученика. После тестирования учащегося базового уровня знаний для каждого курса администратор оценивает учащегося как "умного" (+1) или "немого" (-1) на определенном курсе. Таким образом, knowledge_level
- это значение для соединения студенческого курса.
CREATE TABLE `StudentCourseAssoc` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`studentID` int(10) unsigned DEFAULT NULL,
`courseID` int(10) unsigned DEFAULT NULL,
`knowledge_level` tinyint(1) DEFAULT NULL,
`group_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1144 DEFAULT CHARSET=utf8;
Приложение должно:
Автоматически группировать (он может создавать новую группу или добавлять ученика в существующую группу) учащиеся каждой ветки со следующими условиями
- Умные и немые студенты должны быть в отдельных группах.
- Группа может состоять из нескольких классов. Таким образом, хорошо сочетать 9-й класс с 10-м. И 11-й с градуированным (12-й класс означает выпускник в sql). Но не 10-11. (Будет 2 режима: 9-10, 11-12)
- Группа может состоять из максимум 8 учеников.
- Курсовые комнаты ограничены. Таким образом, каждая комната вмещает всего 5 групп в течение дня.
- Каждый студент должен сидеть на каждом выбранном (самостоятельно) курсе в течение 1 дня.
После поиска group
, который соответствует вышеприведенным условиям, если не найден, приложение должно создать, а затем назначить ученику group
. Тогда:
CREATE TABLE `StudentGroupAssoc` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`group_id` int(10) unsigned DEFAULT NULL,
`student_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
CREATE TABLE `Schedule` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`group_id` int(10) unsigned DEFAULT NULL,
`week_day_mode` tinyint(1) DEFAULT NULL,
`hour` tinyint(1) DEFAULT NULL,
`room_id` int(4) unsigned DEFAULT NULL,
`teacher_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `Unique Room for exact time` (`week_day_mode`,`hour`,`room_id`) USING BTREE,
UNIQUE KEY `Unique Group for exact time` (`group_id`,`week_day_mode`) USING BTREE,
KEY `Unique Teacher for exact time` (`week_day_mode`,`hour`,`teacher_id`),
KEY `room_id` (`room_id`),
KEY `teacher_id` (`teacher_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
И вот скрипка для игры.
Что я сделал
Я пытаюсь поместить ученика в group
(либо существующий, либо создать новый) во время оценки знаний. Например, если студент выбирает Math как один из курсов, когда администратор оценивает свои знания в Math и положительно оценивает, процедура начинает выбирать подходящую группу для этого ученика:
- Функция отмечает уровень knowowledge учащихся.
- Проверяет доступные часы работы студента (скажем, 1-й час уже занят, затем у него есть 4 доступных часа).
- Добавляет условие покрытия класса для поиска (например, 9-10 классы или 11-12 классов).
- Проверяет таблицу расписания, если есть какая-либо группа в доступных часах в недельных планах студентов.
Если его нет, попытайтесь создать.
Итак, представление PHP выглядит так:
//sets knowledge level of student
$studentCourse->knowledge_level = intval($_POST["mark"]);
//check hours of student, and keep only available hours
$availableHours = array_combine(range(1, 5), range(1, 5));
//Unsets students unavailable hours from possible hours
if ($student->GroupRels)
foreach ($student->GroupRels as $groupRel)
unset($availableHours[$groupRel->hour]);
//Checks available groups based on class coverage
if (in_array($student->class, ['11', 'G']))
$classCoverage = "11-m";
else if (in_array($student->class, ['9', '10']))
$classCoverage = "9-10";
$availableGroups = Group::find()
->with("schedule")
->where([
"Group.class_coverage" => $classCoverage,
"Group.knowledge_level" => $studentCourse->knowledge_level,
"Group.participiant_count<8",
"Schedule.hour" => $availableHours,
'Schedule.week_day_mode' => $student->week_day_mode
]
)->all();
if (count($availableGroups) > 0) {
//Selecting one of groups
//adding row to StudentGroupAssoc
//adding row to Schedule
} else {
$group = new Group();
$group->branch_id = $student->branchID;
$group->class_coverage = $classCoverage;
$group->course_id=$studentCourse->courseID;
$group->knowledge_level=$studentCourse->knowledge_level;
$group->save();
...
//adding row to StudentGroupAssoc
//adding row to Schedule
}
Вопрос:
Теоретически, способ, которым я занимаюсь, - это купить билет на самолет. Беспокойный и должен работать, но он не эффективен и не оптимален. Все условия группировки должны выполняться наиболее эффективным способом: минимальное количество групп и соблюдение политики подсчета номеров. Вскоре этот меник будет создавать множество групп, которые не будут соответствовать доступным часам комнат.По мере того, как я занимаюсь студентами один за другим, (во время процесса оценки) становится все труднее получать действительно эффективные результаты. Шанс не набирать группы и не создавать новые группы из-за ограничений в номерах, растет и увеличивается, если учесть количество студентов.
Что вы предлагаете использовать каждый час в каждой комнате?
UPDATE
На основании ответа @norbert_van_nobelen я создал таблицу часов 'dummy' и следующий вид, чтобы получить список возможных комбинаций номеров по комнате для каждого ученика.
hours
реальный планируемый час
hours_available
- это двоичный ключ.
Итак, в реальном коде мы добавляем предложение where: WHERE hours_available = 0, чтобы получить только часы, которые мы планируем против:
SELECT
`s`.`id` AS `student_id`,
IF ((ifnull(`sch`.`hour`, 0) > 0), 1, 0) AS `hour_available`,
`d`.`hours` AS `hours`,
`sca`.`courseID` AS `courseID`,
`sch`.`room_id` AS `room_id`,
`sca`.`knowledge_level` AS `knowledge_level`,
(
CASE
WHEN (
(`s`.`class` = 9)
OR (`s`.`class` = 10)
) THEN
'9-10'
WHEN (
(`s`.`class` = 11)
OR (`s`.`class` = 12)
) THEN
'11-12'
ELSE
'??'
END
) AS `class_variant`
FROM
(
(
(
(
`dummy_hours` `d`
JOIN `Student` `s`
)
LEFT JOIN `StudentCourseAssoc` `sca` ON ((`s`.`id` = `sca`.`studentID`))
)
LEFT JOIN `StudentGroupAssoc` `b` ON ((`s`.`id` = `b`.`student_id`))
)
LEFT JOIN `Schedule` `sch` ON (
(
(
`sch`.`group_id` = `b`.`group_id`
)
AND (`d`.`hours` = `sch`.`hour`)
)
)
)
Использование этого представления дает полную картину текущей ситуации. Но я все еще не могу понять алгоритм
- разместить учащихся в группах
- размещение групп в номерах
наиболее эффективным, оптимальным способом с минимальным созданием количества групп.
Любые предложения?