1

我有一个看起来像这样的表:

studentID | subjectID | attendanceStatus | classDate  | classTime | lecturerID |
12345678    1234        1                  2012-06-05   15:30:00
87654321
12345678    1234        0                  2012-06-08   02:30:00

我想要一个查询,报告学生是否连续缺席 3 个或更多课程。基于 studentID 和 2 个特定日期之间的特定主题。每个班级可以有不同的时间。该表的架构是:

PK(`studentID`, `classDate`, `classTime`, `subjectID, `lecturerID`)

出勤状态:1 = 出席,0 = 缺席

编辑:措辞问题,使其更准确,并真正描述了我的意图。

4

3 回答 3

1

我无法为此创建 SQL 查询。因此,我尝试了一个 PHP 解决方案:

  1. 从表中选择所有行,按学生、学科和日期排序
  2. 为缺勤创建一个运行计数器,初始化为0
  3. 遍历每条记录:
    • 如果学生和/或科目与前一行不同
      • 将计数器重置为 0(存在)或 1(不存在)
    • 否则,即学生和科目相同时
      • 将计数器设置为 0(存在)或加 1(不存在)

然后我意识到这个逻辑可以很容易地使用 MySQL 变量来实现,所以:

SET @studentID = 0;
SET @subjectID = 0;
SET @absentRun = 0;

SELECT *,
CASE
    WHEN (@studentID  = studentID) AND (@subjectID  = subjectID) THEN @absentRun := IF(attendanceStatus = 1, 0, @absentRun + 1)
    WHEN (@studentID := studentID) AND (@subjectID := subjectID) THEN @absentRun := IF(attendanceStatus = 1, 0, 1)
END AS absentRun
FROM table4
ORDER BY studentID, subjectID, classDate

您可能可以将此查询嵌套在另一个选择记录 where 的查询中absentRun >= 3

SQL小提琴

于 2012-05-12T16:54:41.010 回答
0

此查询适用于预期结果:

SELECT DISTINCT first_day.studentID 
FROM student_visits first_day
LEFT JOIN student_visits second_day
    ON first_day.studentID = second_day.studentID
    AND DATE(second_day.classDate) - INTERVAL 1 DAY = date(first_day.classDate)
LEFT JOIN student_visits third_day
    ON first_day.studentID = third_day.studentID
    AND DATE(third_day.classDate) - INTERVAL 2 DAY = date(first_day.classDate)
WHERE first_day.attendanceStatus = 0 AND second_day.attendanceStatus = 0 AND third_day.attendanceStatus = 0

它在每个学生的连续 3 个日期上将表“student_visits”(让我们这样命名您的原始表)逐步连接到自身,最后检查这些天的缺勤情况。Distinct 确保结果不会包含超过连续缺勤 3 天的重复结果。

此查询不考虑特定主题的缺勤 - 只是每个学生连续缺勤 3 天或更长时间。要考虑主题,只需在每个 ON 子句中添加 .subjectID :

    ON first_day.subjectID = second_day.subjectID

PS:不确定这是最快的方式(至少它不是唯一的)。

于 2012-05-12T09:55:03.200 回答
0

不幸的是,mysql 不支持 windows 功能。使用 row_number() 或更好的累积总和(如 Oracle 支持)会更容易。

我将描述解决方案。假设您的表中有两个额外的列:

  • ClassSeqNum - 一个从 1 开始并为每个课程日期递增 1 的序列。
  • AbsentSeqNum - 每次学生缺课时从 1 开始的序列,然后在每次缺课时增加 1。

关键的观察是这两个值之间的差异对于连续缺席是恒定的。因为您使用的是 mysql,您可能会考虑将这些列添加到表中。在查询中添加它们是很大的挑战,这就是为什么这个答案这么长。

鉴于关键观察,您的问题的答案由以下查询提供:

select studentid, subjectid, absenceid, count(*) as cnt
from (select a.*,  (ClassSeqNum - AbsentSeqNum) as absenceid
      from Attendance a
     ) a
group by studentid, subjectid, absenceid
having count(*) > 2

(好的,这给出了每个科目的学生缺勤的每个顺序,但我认为您可以弄清楚如何将其缩减为学生列表。)

你如何分配序列号?在 mysql 中,您需要进行自连接。因此,以下添加了 ClassSeqNum:

select a.StudentId, a.SubjectId, count(*) as ClassSeqNum
from Attendance a join
     Attendance a1
     on a.studentid = a1.studentid and a.SubjectId = a1.Subjectid and
        a.ClassDate >= s1.classDate
group by a.StudentId, a.SubjectId

以下添加缺席序列号:

select a.StudentId, a.SubjectId, count(*) as AbsenceSeqNum
from Attendance a join
     Attendance a1
     on a.studentid = a1.studentid and a.SubjectId = a1.Subjectid and
        a.ClassDate >= a1.classDate
where AttendanceStatus = 0
group by a.StudentId, a.SubjectId

所以最终的查询看起来像:

with cs as (
    select a.StudentId, a.SubjectId, count(*) as ClassSeqNum
    from Attendance a join
         Attendance a1
         on a.studentid = a1.studentid and a.SubjectId = a1.Subjectid and
            a.ClassDate >= s1.classDate
    group by a.StudentId, a.SubjectId
),
    a as (
    select a.StudentId, a.SubjectId, count(*) as AbsenceSeqNum
    from Attendance a join
         Attendance a1
         on a.studentid = a1.studentid and a.SubjectId = a1.Subjectid and
            a.ClassDate >= s1.classDate
    where AttendanceStatus = 0
    group by a.StudentId, a.SubjectId
)
select studentid, subjectid, absenceid, count(*) as cnt
from (select cs.studentid, cs.subjectid,
             (cs.ClassSeqNum - a.AbsentSeqNum) as absenceid 
      from cs join
           a
           on cs.studentid = a.studentid and cs.subjectid = as.subjectid
     ) a
group by studentid, subjectid, absenceid
having count(*) > 2
于 2012-05-12T15:03:35.767 回答