TSQL Подсчет количества последовательных пропусков подряд - PullRequest
1 голос
/ 29 марта 2011

Задача: * Я пытаюсь подсчитать количество последовательных пропусков занятий каждого ученика в определенном классе.Однако необходимо возобновить подсчет, если этот ученик посещал занятия в течение одного дня.

например, если в классе MATH1234 есть занятия в понедельник и пятницу, а ученик 001234 пропустилПонедельник, пятница для Недели 1 и понедельник для Недели 2, но посещенные Пятница для Недели 2, затем пропущенные понедельник и пятница для Недели 3, их число последовательных пропусков для этого класса будет:

(это сокращенная версиямоей таблицы уроков)

Class Day Week    IsAbsent    ConsecutiveAbs
MATH1234  Mon 1   1       1
MATH1234  Fri 1   1       2
MATH1234  Mon 2   1       3
MATH1234  Fri 2   0       0
MATH1234  Mon 3   1       1
MATH1234  Fri 3   1       2

У меня есть таблица под названием Уроки , в которой содержится текущий список всех учащихся и классов, в которые они записаны, а такжеони отсутствовали в любых классах:

Уроки ([ID ученика], [Номер класса], [Номер строки], [Академический период], [Год], [Срок], [Неделя], [Период дня], [ClassDate], [IsAbsent], [ReasonCode], [ConsecutiveAbs])

Учитывая приведенную выше таблицу, в настоящее время я занимаюсь обновлением таблицы «Уроки» и изменяю значение ConsecutiveAbsкак это:

UPDATE Lessons
SET ConsecutiveAbs = 
(SELECT ISNULL(SUM(CAST(IsAbsent AS numeric)), 0)
 FROM Lessons AS L3
 WHERE L3.IsAbsent = 1
 AND L1.IsAbsent <> 0
 AND L3.[Student ID] = L1.[Student ID]
 AND L3.[Class Number] = L1.[Class Number]
 AND L3.[Line Number] = L1.[Line Number]
 AND L3.[Year] = L1.[Year]
 AND L3.[ClassDate] <= L1.[ClassDate]
 AND (L3.[ClassDate] > (SELECT MAX(L2.ClassDate)
      FROM Lessons AS L2
      WHERE L2.IsAbsent = 0
      AND L2.[Student ID] = L1.[Student ID]
      AND L2.[Class Number] = L1.[Class Number]
      AND L2.[Line Number] = L1.[Line Number]
      AND L2.[Year] = L1.[Year]
      AND L2.ClassDate < L1.[ClassDate]
 ) OR (SELECT MAX(L2.ClassDate)
       FROM Lessons AS L2
       WHERE L2.IsAbsent = 0
       AND L2.[Student ID] = L1.[Student ID]
       AND L2.[Class Number] = L1.[Class Number]
       AND L2.[Line Number] = L1.[Line Number]
       AND L2.[Year] = L1.[Year]
       AND L2.ClassDate < L1.[ClassDate]
 ) IS NULL))
 FROM Lessons AS L1

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

Class Day Week    IsAbsent    ConsecutiveAbs

MATH1234  Mon 1   1       1
MATH1234  Fri 1   1       2
MATH1234  Mon 2   1       3
MATH1234  Fri 2   0       4
MATH1234  Mon 3   1       5
MATH1234  Fri 3   1       6

Есть идеи?

Ответы [ 4 ]

1 голос
/ 30 марта 2011

Подобно ответу на ваш предыдущий вопрос, только на этот раз он ищет посещаемый класс, а не просто ограничивает поиск неделей.

UPDATE allLessons
SET ConsecutiveAbs = results.ConsecutiveAbs
FROM 
    Lessons allLessons JOIN
(
    SELECT 
        LessonsAbsent.[Student ID],
        LessonsAbsent.[Class Number],
        LessonsAbsent.[Line Number],
        LessonsAbsent.[Year],
        LessonsAbsent.ClassDate,
        ISNULL(SUM(CAST(IsAbsent AS numeric)), 0) AS ConsecutiveAbs
    FROM 
        Lessons LessonsAbsent JOIN
        Lessons RunningTotalAbsent ON 
            RunningTotalAbsent.IsAbsent = 1
            AND LessonsAbsent.[Student ID] = RunningTotalAbsent.[Student ID]
            AND LessonsAbsent.[Class Number] = RunningTotalAbsent.[Class Number]
            AND LessonsAbsent.[Line Number] = RunningTotalAbsent.[Line Number]
            AND LessonsAbsent.[Year] = RunningTotalAbsent.[Year]
            AND LessonsAbsent.ClassDate >= RunningTotalAbsent.ClassDate

            -- Only include this date in the running total only if the student has not attended a class in-between the absences.
            AND NOT EXISTS (
                SELECT *
                FROM Lessons notAbsent
                WHERE 
                    LessonsAbsent.[Student ID] = notAbsent.[Student ID]
                    AND LessonsAbsent.[Class Number] = notAbsent.[Class Number]
                    AND LessonsAbsent.[Line Number] = notAbsent.[Line Number]
                    AND LessonsAbsent.[Year] = notAbsent.[Year]
                    AND notAbsent.IsAbsent = 0
                    AND notAbsent.ClassDate <= LessonsAbsent.ClassDate
                HAVING MAX(ClassDate) > RunningTotalAbsent.ClassDate
        )
    WHERE LessonsAbsent.IsAbsent = 1   
    GROUP BY
        LessonsAbsent.[Student ID],
        LessonsAbsent.[Class Number],
        LessonsAbsent.[Line Number],
        LessonsAbsent.[Year],
        LessonsAbsent.ClassDate
) results ON
    results.[Student ID] = allLessons.[Student ID]
    AND results.[Class Number] = allLessons.[Class Number]
    AND results.[Line Number] = allLessons.[Line Number]
    AND results.[Year] = allLessons.[Year]
    AND results.ClassDate = allLessons.ClassDate
0 голосов
/ 29 марта 2011

Не уверен, если вы хотите придерживаться идеи подзапроса.Эта проблема типа -IMO лучше решается (быстрее, менее сложна) с помощью курсоров.Вот как будет выглядеть SQL, если вы выберете этот путь.

Поэтому я не позволил вставить код в ответ.Итак, я вставил фрагмент кода здесь.http://pastebin.com/ybesdX2G

Вот ссылка на статью, показывающую, как делать курсоры.http://msdn.microsoft.com/en-us/library/ms180169.aspx

Редактировать: Курсорный подход работает по одной строке за раз и запоминает, отсутствовала / была ли последняя строка.Поэтому важно правильно отсортировать данные.

Обратите внимание, что в фрагменте кода нет ORDER BY.Я протестировал фрагмент кода на примере данных, которые вы предоставили в вопросе.Ваши данные были предварительно отсортированы.Итак, это сработало как шарм.

В вашей базе данных, если ваши данные не сохранены в предварительно отсортированном виде (что я сомневаюсь, что это так), вы захотите добавить ORDER BY в строку # 8,чтобы отсортировать данные в последовательности.

Надеюсь, это поможет.

0 голосов
/ 29 марта 2011

Это может быть бесполезно в зависимости от вашего сценария, но может помочь вам найти решение

select * 
into #orderedlessons
from Lessons
order by [Student ID], [Class Number], [Line Number], [Year], [ClassDate]

declare @tot int
set @tot=0
update #orderedlessons
set @tot = ConsecutiveAbs = Case when IsAbsent=0 then 0 else @tot+1 END;

update lessons
set lessons.ConsecutiveAbs = ordered.ConsecutiveAbs
from lessons inner join  #orderedlessons ordered on
lessons.[Student ID] = ordered.[Student ID]
and lessons.[Class Number] = ordered.[Class Number]
and lessons.[Line Number] = ordered.[Line Number]
and lessons.[Year] = ordered.[Year]
and lessons.ClassDate = ordered.[ClassDate]

drop table #orderedlessons
0 голосов
/ 29 марта 2011

Как-то так?

update L2
set L2.ConsecutiveAbs = 
        case 
        when L2.IsAbsent = 0 then 0
        else (  select  TOP 1 L1.ConsecutiveAbs 
                from    Lessons L1
                where   L2.[Student ID] = L1.[Student ID]
                    AND L2.[Class Number] = L1.[Class Number]
                    AND L2.[Line Number] = L1.[Line Number]
                    AND L2.[Year] = L1.[Year]
                    AND L2.ClassDate > L1.[ClassDate]
                ORDER BY L1.ClassDate desc
              )
        end as ConsecutiveAbs
from    Lessons L2

Редактировать: Добавить свое обновление вокруг.

Редактировать2: Добавлено обновление

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...