Общее количество активных студентов - PullRequest
0 голосов
/ 17 мая 2019

В SQL у меня есть таблица со студентами:

CREATE TABLE dbo.[Student]
(
  [Id] bigint IDENTITY(1,1) NOT NULL CONSTRAINT [PK_Student] PRIMARY KEY NONCLUSTERED,
  [ActiveFrom] [DATETIME] NOT NULL,
  [ActiveUntil] [DATETIME] NULL,
) ON [PRIMARY]

Теперь я хочу показать гистограмму, сколько студентов было активным в каждом месяце года.Студент активен в течение месяца, если [ActiveFrom] раньше или в этом месяце, а [ActiveUntil] равен нулю или позже, или в этом месяце.

Я полагаю, мне нужна какая-то группа, но поскольку студентможет быть активным в течение нескольких месяцев или лет. Я понятия не имел, как получить эти числа в одной команде SQL.

Пример ввода

INSERT INTO Student (ActiveFrom, ActiveUntil)  VALUES ('20181001', '20181231')
INSERT INTO Student (ActiveFrom, ActiveUntil)  VALUES ('20181101', '20190131')
INSERT INTO Student (ActiveFrom, ActiveUntil)  VALUES ('20181201', '20181231')
INSERT INTO Student (ActiveFrom, ActiveUntil)  VALUES ('20190101', '20190430')

Ожидаемый результат

Month,   Activecount
2018-10, 1
2018-11, 2
2018-12, 3
2019-01, 2
2019-02, 1
2019-03, 1
2019-04, 1

1 Ответ

1 голос
/ 17 мая 2019
DECLARE @ReportStartDate DATE = '20180101'
    , @ReportEndDate DATE = '20191231'
; WITH MonthCounter AS
(
    SELECT 1 i 
    UNION ALL
    SELECT i+1 i 
        FROM MonthCounter
        WHERE i < DATEDIFF(MONTH, @ReportStartDate, @ReportEndDate)
) 
, Months AS
(
    SELECT DATEADD(MONTH, i-1, @ReportStartDate) AS StartDate
        , DATEADD(DAY, -1, DATEADD(MONTH, i, @ReportStartDate)) AS EndDate
    FROM MonthCounter
) 
SELECT mo.StartDate
    , mo.EndDate
    , COUNT(st.[Key]) AS ActiveStudents
FROM Months mo
    LEFT JOIN Student st ON DATEDIFF(DAY, st.ActiveFrom, mo.enddate) >= 0
        AND (st.ActiveUntil IS NULL OR DATEDIFF(DAY, mo.startdate, st.ActiveUntil) >= 0)
GROUP BY mo.startdate
    , mo.enddate
ORDER BY mo.startdate
OPTION (MAXRECURSION 0)

Извиняюсь за сложный месяц, генерирующий код, но я действительно попытался сделать это одним запросом SELECT, и я не смог найти намного лучший метод, чем рекурсивный CTE.

Обратите внимание на сравнение. Чтобы определить, является ли студент активным в течение месяца, ActiveFrom записи должен начинаться где-то ДО КОНЦА конца месяца, а ActiveTo должен быть какой-то датой или ПОСЛЕ НАЧАЛА месяца.

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