получить список студентов с посещаемостью не менее 15 дней в месяц и приходить на непрерывные 4 месяца в году - PullRequest
0 голосов
/ 03 октября 2018

Мне нужен запрос, чтобы получить список студентов, посещавших там урок, по крайней мере, 15 дней в месяц в течение непрерывных 4 месяцев.

таблица может выглядеть как

studentid   monthyear   attendance
1            Apr2018      16
1            May2018      23
1            Jun2018      18
1            Jul2018      16
1            Aug2018      25
2            Apr2018      2
2            May2018      15

и так далее...

Db fiddle

Ответы [ 3 ]

0 голосов
/ 03 октября 2018

В общем случае достаточно простого самопроизвольного объединения, которое бы улавливало разницу месяцев. В этом случае требуется преобразование столбца monthyear в самой команде объединения

Запрос без преобразования:

SELECT t1.studentid, count(*) as cnt
FROM
table t1
INNER JOIN table t2 ON t1.studentid = t2.studentid AND
t2.attendance >= 15
AND t1.monthyear BETWEEN t2.monthyear AND (t2.monthyear - 3)
WHERE 
t1.attendance >= 15
GROUP BY
studentid
HAVING
count(*)  >=4

Преобразование выглядит следующим образом:

STR_TO_DATE(
CONCAT(SUBSTR(t1.monthyear,1, LENGTH(t1.monthyear) - 4),' ', RIGHT(t1.monthyear, 4), %M %Y)

, поэтому запрос должен быть:

SELECT t1.studentid, count(*) as cnt
    FROM
    table t1
    INNER JOIN table t2 ON t1.studentid = t2.studentid AND
    t2.attendance >= 15
    AND STR_TO_DATE(
    CONCAT(SUBSTR(t1.monthyear,1, LENGTH(t1.monthyear) - 4),' ', RIGHT(t1.monthyear, 4), %M %Y) BETWEEN STR_TO_DATE(
    CONCAT(SUBSTR(t2.monthyear,1, LENGTH(t2.monthyear) - 4),' ', RIGHT(t2.monthyear, 4), %M %Y) AND DATE_SUB(STR_TO_DATE(
    CONCAT(SUBSTR(t2.monthyear,1, LENGTH(t2.monthyear) - 4),' ', RIGHT(t2.monthyear, 4), %M %Y), INTERVAL 3 MONTH) 
    WHERE 
    t1.attendance >= 15
    GROUP BY
    studentid
    HAVING
    count(*)  >=4
0 голосов
/ 03 октября 2018

Я думаю, что это самый простой метод:

select distinct studentid
from (select t.*, cast(monthyear as date) as my,
             lag(cast(monthyear as date), 3) over (partition by studentid order by cast(monthyear as date)) as prev_my
      from tbl t
      where attendance >= 15
     ) t
where prev_my = dateadd(month, -3, my);

Вот дБ <> скрипка .

Логика довольно проста:

  • Рассматривать только те строки, которые удовлетворяют критерию посещаемости.
  • Используйте LAG() для просмотра третьей записи в прошлом.
  • Если все месяцы соответствуют критерию посещаемости, то это будетбыть ровно за 3 месяца до этого.

select distinct - это потому, что вы хотите студентов, а не конкретные периоды.

0 голосов
/ 03 октября 2018

Попробуйте этот запрос:

select @rn := 0;
select studentid from (
  select studentid, month(dt) - (@rn := @rn + 1) grp from (
    select * ,
           str_to_date(concat('01 ', insert(monthyear, 4, 0, ' ')), '%d %M %Y') dt
    from tbl
    where attendance >= 15 --only those records, where attenadnce is at least 15
  ) a where year(dt) = 2018 --particular year
  order by studentid,dt
) a group by studentid,grp having count(*) >= 4

Демо - я расширил ваши данные еще несколькими случаями:)

Идея проста - если студент посещалнекоторые последовательные месяцы, последовательные месяцы будут увеличиваться на единицу, точно так же как номер строки, поэтому я использовал разницу между месяцами и номерами строк - для последовательных месяцев разница должна быть постоянной, поэтому достаточно сгруппировать эту разницу и взять те группы, гдеколичество>> 4:)

ОБНОВЛЕНИЕ

Для SQL Server:

select studentid from (
  select studentid, month(dt) - row_number() over (order by studentid, dt) grp from (
    select * ,
           cast(concat('01 ', stuff(monthyear, 4, 0, ' ')) as date) dt
    from tbl
    where attendance >= 15 --only those records, where attenadnce is at least 15
  ) a where year(dt) = 2018 --particular year
) a group by studentid, grp having count(*) >= 4

Демонстрация SQL Server

...