在职学生总数

时间:2019-05-17 09:37:25

标签: sql-server

在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 个答案:

答案 0 :(得分:1)

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必须在该月的开始日期或之后的某个日期。