У меня есть система посещаемости в одном из моих модульных проектов с использованием PHP и MySQL, таблица MySQL выглядит примерно так:
Теперь расписание используется для хранения таблицы времени для классов за один день для раздела и для которого назначен учитель. Таблица student_info содержит общую информацию о студентах и разделе, к которому они принадлежат. Присутствующий используется для записи тех, кто отсутствует, используя время и идентификатор студента в качестве первичного ключа.
Я мог бы подсчитать, сколько классов было проведено в семестр следующим образом:
SELECT count(*) as total FROM timetable WHERE flag > ? AND semester = ? AND section = ? AND timeid BETWEEN ? AND ?
Затем вычисляли, сколько раз посещал студент, а также подсчитывали процент посещаемости.
SELECT stu.* , (SELECT COUNT(*) FROM attendancetable att WHERE att.s_id = stu.class_roll AND att.semester = ? AND att.timeid BETWEEN ? AND ? ) AS absent FROM student_info stu WHERE stu.section = ? AND stu.logYear = ? AND stu.deleted = ? ORDER BY stu.class_roll
Теперь я хочу также отобразить вид листа посещаемости следующим образом:
Я попробовал SQL Inner Join, но не получил того, чего хотел.
Я думал, что первая строка может быть выведена из следующего запроса:
SELECT timeid FROM timetable WHERE flag > ? AND semester = ? AND section = ? AND timeid BETWEEN ? AND ?
[UPDATE] Найден способ сделать это, учитывая как ответ, не знаю, правильно ли это.
Заранее благодарю за помощь.
Я, наверное, немного опоздал с моим ответом, но я тоже немного поиграл и придумал решение, которое в основном выполняется в MySql: мое решение создает динамическую SELECT
которая выполняется в конце, чтобы предоставить мне таблица, имеющая столбцы, охватывающие предопределенную эру:
SET @str='SELECT sid'; SELECT @str:=concat(@str,', MAX(CASE tid WHEN ',t_id, ' THEN \'OK\' ELSE \'\' END) d',t_id) -- start date end date FROM times WHERE dati BETWEEN '20170810.0000' and '20171022.2359'; SET @str=concat(@str,' FROM att GROUP BY sid'); PREPARE qu FROM @str; EXECUTE qu;
Что еще нужно сделать, так это перевод идентификаторов дат в заголовках столбцов на соответствующие даты и, также, перевод идентификаторов студентов в имена или номера univ_roll
.
Я также немного поменял макет таблицы: первичный ключ в расписании теперь всего лишь целое число, фактическое время хранится отдельно в другом столбце, обеспечивая гибкость в случае, когда даты или времена могут измениться.
Вот небольшая демонстрация реестров: http://rextester.com/LPFF99061 (таблица посещаемости была заполнена только для первых нескольких дат).
Я не уверен, должен ли я редактировать вопрос с этими обновлениями. Но это частичное решение, с которым я столкнулся. Был бы рад, если бы кто-то мог помочь оптимизировать это больше.
Итак, я начал с этой части кода.
SELECT timeid FROM timetable WHERE flag > ? AND semester = ? AND section = ? AND timeid BETWEEN ? AND ?
Из приведенного выше кода я мог бы получить даты, где будут выполняться занятия. Далее, я проверяю, присутствует ли студент или отсутствует в указанные ниже даты:
SELECT attended FROM attendancetable WHERE s_id = ? AND semester = ? AND timeid = ?
С этим я смог узнать, отсутствует ли студент или нет. В php это выглядит примерно так:
//Getting the dates $query = "SELECT timeid FROM timetable WHERE flag > ? AND semester = ? AND section = ? AND timeid BETWEEN ? AND ?"; $params = array(0, 1, 'A', '2017-01-01', '2017-06-30' ); $stmt = $db->prepare($query); $stmt->execute($params); $dates = $stmt->fetchall(); //checking if students is present or absent $query = "SELECT attended FROM attendancetable WHERE s_id = ? AND semester = ? AND timeid = ?"; //Now I'm going to loop through the $dates foreach($dates as $date){ $params = array(1, 'A', $date['timeid']); $stmt = $db->prepare($query); $stmt->execute($params); $result = $stmt->fetchall(); ($result) ? $present = 1 : $present = 0; }
Таким образом, я смог вычислить, присутствует ли ученик определенного раздела или отсутствует для данного класса в соответствии с расписанием. Теперь, если я хочу, чтобы все учащиеся в секции могли сначала запросить таблицу student_info
а затем вычислить цикл foreach
для каждого отдельного ученика
SELECT class_roll FROM student_info WHERE logYear = ? AND section = ? AND deleted = ? ORDER BY class_roll LIMIT ?, ?
Затем каждый студент проходит через цикл foreach, чтобы проверить, отсутствуют ли они или нет. Наконец, я мог бы получить следующее:
Я тестировал время выполнения локально для примерно 200 учеников, до примерно 1,6 секунды, когда количество классов составляет всего 39. Я тестирую предыдущие данные и на весь семестр, а код превышает 30 секунд и срабатывает ошибка max_execution_time
. На данный момент я установил 25 номеров студентов на каждую страницу.
UPDATE : Ошибка max_execution_time
кажется, появляется только в первом запуске, но позже, когда я пытаюсь повторно создать ее, не выдавая больше ошибки, и время, затраченное на выполнение задачи, составляет менее 2 секунд.