我有一个具有以下结构的表:
StartDate datetime NOT NULL
EndDate datetime NOT NULL
EnrollmentId nvarchar(255) NOT NULL
ProgrammeId nvarchar(255) not null
EnrollmentId
是主键,有点像GUID字符串,ProgrammeId
指的是'主题代码',有点像GUID。
我想要做的是确定Programme
在所有注册的特定日期范围内累计的总月数,例如从2011年1月1日到2014年4月1日。
因此,假设我在08/08/2010
到01/01/2012
之间存在针对特定programmeId
的注册。我希望计算01/01/2011
之后累积的所有月份。因此,在此日期之前的任何月份都不应计算,即08/08/2010至2010年12月31日不应计算在内。
理想情况下,我希望计算给定日期范围内每ProgrammeId
个月的数量。
只是几点说明:
一些代码可以返回注册的所有月份:
;with MonthList as (
select
DATEADD(month, M, '12/1/1899') as 'FirstDay',
dateadd(day, -1, dateadd(month, M + 1, '12/1/1899')) as 'LastDay',
DATEADD(month, M + 1, '12/1/1899') as 'FirstDayNextMonth'
from (
select top 3000 ROW_NUMBER() over (order by s.name) as 'M'
from master..spt_values s) s
)
select
t.ProgrammeId, ml.FirstDay, ml.LastDay
from
Enrollment t
inner join MonthList ml
on t.startdate < ml.FirstDayNextMonth
and t.enddate >= ml.FirstDay
提前致谢
答案 0 :(得分:0)
我以为我有一个答案,但你的更新让我对你真正想要的东西感到困惑。我包括the statement I wrote (SQL Fiddle),希望它会有所帮助。
SELECT ProgrammeId,
DATEDIFF(MONTH,
CASE WHEN '2011-01-01 00:00:00' > MIN(StartDate) THEN '2011-01-01 00:00:00'
ELSE MIN(StartDate)
END,
CASE WHEN '2014-04-01 00:00:00' < MAX(EndDate) THEN '2014-04-01 00:00:00'
ELSE MAX(EndDate)
END
) As Months
FROM ProgrammeEnrollment
GROUP BY ProgrammeID
;
SQL Server没有GREATEST
和LEAST
,因此我不得不使用CASE
语句进行即兴创作。如果您使用的是具有GREATEST
和LEAST
的RDBMS,那么它们将替代CASE
语句。
答案 1 :(得分:0)
设置一些样本数据:
CREATE TABLE #tbl (
EnrollmentId INT NOT NULL --NOTE: using INT instead of your VARCHAR becuas eit easier and doesn't matter in sample
,ProgrammeId INT NOT NULL
,StartDate DATETIME NOT NULL
,EndDate DATETIME NOT NULL
)
INSERT INTO #tbl VALUES
(1,1,'2013-01-01','2014-01-01'),
(2,1,'2013-07-01','2014-01-01'),
(3,2,'2013-01-01','2014-01-01')
(4,3,'2013-01-15','2014-03-01')
现在声明搜索范围并进行查询
DECLARE @RangeStart DATETIME = '2013-01-01'
DECLARE @RangeEnd DATETIME = '2013-12-01'
;WITH cte AS (
SELECT EnrollmentId
,ProgrammeId
,CASE WHEN @RangeStart >= StartDate THEN @RangeStart ELSE StartDate END EffectStartDate
,CASE WHEN @RangeEnd <= EndDate THEN @RangeEnd ELSE EndDate END EffectEndDate
FROM #tbl
WHERE @RangeStart BETWEEN StartDate AND EndDate --start date is in range
OR @RangeEnd BETWEEN StartDate AND EndDate --or end date is in range
OR (EndDate > @RangeEnd AND StartDate < @RangeStart) --or period contains the range
)
SELECT ProgrammeId
,SUM(dbo.FullMonthsSeparation(EffectStartDate,EffectEndDate)) Months
FROM cte
GROUP BY ProgrammeId
样本结果:
ProgrammeId Months
----------- -----------
1 16
2 11
3 10