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

おそらく、このクエリを、レコードを選択する別のクエリ内にネストできます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

テーブル「student_visits」(元のテーブルに名前を付けましょう)を、各学生の連続した3つの日付で段階的に結合し、最終的にこれらの日の欠席をチェックします。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 でサポートされている) を使用すると、はるかに簡単になります。

解決策を説明します。テーブルに 2 つの追加の列があるとします。

  • ClassSeqNum -- 1 から始まり、クラスの日付ごとに 1 ずつ増加するシーケンス。
  • AbsentSeqNum -- 生徒がクラスを欠席するたびに 1 から始まり、その後欠席するたびに 1 ずつ増加するシーケンス。

重要な観察結果は、これら 2 つの値の差は、連続して欠席する場合は一定であるということです。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 に答える