我正在计算一周重复的CTE,但当模式跨过一年时,我遇到一些问题。T-SQL计算日期的重现
的CTE应 计算基于以下参数的所有事件:
- 复发次数 - 多少次它会发生
- 周天 - 在一周中的一天它会发生
- 开始日期 - 当模式计算开始时
- 周期 - 如何往往在几周而言,每周即1,2,每2周
- 开始周 - 中首次出现的周数,它反映开始日期列
这就是我如何存储模式:
/*
Pattern Table
*/
CREATE TABLE Pattern (
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY
, [Subject] [nvarchar](100) NULL
, [RecurrenceCount] [int] NULL
, [WeekDays] [varchar](max) NULL
, [StartDate] [datetime] NULL
, [EndDate] [datetime] NULL
, [Periodicity] [int] NULL
, [StartingWeek] [int] NULL
);
下面是一对夫妇的模式我使用来测试我的CTE:
/*
Pattern samples for test
*/
Insert into Pattern Values (N'Every 5 Weeks Fri, Sat, Sun', 72, 'Friday, Saturday, Sunday', N'2016-12-02', N'2016-12-02', 5, datepart(wk, N'2016-12-02'));
Insert into Pattern Values (N'Every 3 Weeks Tue, Wed, Thu', 20, 'Tuesday, Wednesday, Thursday', N'2016-11-01', N'2016-11-01', 3, datepart(wk, N'2016-11-01'));
我开始计数考虑周的第一天星期一
SET DATEFIRST 1
,这是CTE我来运行这些计算:
/*
Display Patterns
*/
select * from Pattern
DECLARE @mindate DATE = (SELECT MIN(StartDate) FROM Pattern)
DECLARE @maxmindate DATE = (SELECT MAX(StartDate) FROM Pattern)
DECLARE @maxcount INT = (SELECT MAX(RecurrenceCount) FROM Pattern)
DECLARE @maxdate DATE = DATEADD(WK, @maxcount + 10, @maxmindate)
/*
CTE to generate required occurrences
*/
;With cteKeyDate As (
Select
KeyStartDate = @MinDate,
KeyDOW = DateName(WEEKDAY, @MinDate),
KeyWeek = datepart(WK,@MinDate)
Union All
Select
KeyStartDate = DateAdd(DD, 1, df.KeyStartDate) ,
KeyDOW = DateName(WEEKDAY,DateAdd(DD, 1, df.KeyStartDate)),
KeyWeek= DatePart(WK,DateAdd(DD, 1, df.KeyStartDate))
From cteKeyDate DF
Where DF.KeyStartDate <= @MaxDate
)
SELECT
Id, KeyStartDate, KeyDow, KeyWeek, RowNr, OccNr = ROW_NUMBER() OVER (PARTITION BY Id ORDER BY StartDate)
FROM
(Select
A.Id
,A.StartDate
,A.EndDate
,Count = A.RecurrenceCount
,Days = A.WeekDays
,Every = A.Periodicity
,KeyStartDate = CASE
/*
if no periodicity (1) then it is sequential
if periodicity, first week doesn't apply (MIN KeyWeek)
*/
WHEN A.Periodicity = 1
OR (Periodicity <> 1 AND (SELECT MIN(C.StartingWeek) FROM Pattern AS C WHERE C.Id = A.Id) = KeyWeek)
THEN KeyStartDate
/* Otherwise formula ADD WEEKS => Current Week Min Week */
ELSE
DATEADD(WK, ((A.Periodicity - 1) * (KeyWeek - (SELECT MIN(C.StartingWeek) FROM Pattern AS C WHERE C.Id = A.Id))) , KeyStartDate)
END
,KeyDow
,KeyWeek
,RowNr = Row_Number() over (Partition By A.Id Order By B.KeyStartDate)
,Periodicity = A.Periodicity
from
Pattern A
Join cteKeyDate B on B.KeyStartDate >= DATEADD(DAY, -1, A.StartDate) and Charindex(KeyDOW, A.WeekDays) > 0
) Final
Where
RowNr <= Count AND Id = 1
Option (maxrecursion 32767)
现在,如果我再次测试我的例如,第一个模式,我得到了这个结果,这个结果在下一年发生时会有错误。 RowNr 15是错误的,因为它应该发生在4月23日(星期天),而不是下周。
Id KeyStartDate KeyDow KeyWeek RowNr OccNr
1 02.12.2016 Friday 49 1 1
2 03.12.2016 Saturday 49 2 2
3 04.12.2016 Sunday 49 3 3
4 06.01.2017 Friday 50 4 4
5 07.01.2017 Saturday 50 5 5
6 08.01.2017 Sunday 50 6 6
7 10.02.2017 Friday 51 7 7
8 11.02.2017 Saturday 51 8 8
9 12.02.2017 Sunday 51 9 9
10 17.03.2017 Friday 52 10 10
11 18.03.2017 Saturday 52 11 11
12 19.03.2017 Sunday 52 12 12
13 21.04.2017 Friday 53 13 13
14 22.04.2017 Saturday 53 14 14
15 28.04.2013 Sunday 1 15 15
16 31.05.2013 Friday 2 16 16
17 01.06.2013 Saturday 2 17 17
虽然第二个模式计算得很好。我认为当模式跨越了一年,并且在SQL中重置为0的周数时,我在逻辑上存在问题,但是我找不到解决方案,因此我现在挣扎了好几天。
您可以使用示例here执行代码。
作为参考点,你并不需要一个'PARTITION BY'在'ROW_NUMBER'和*请*不A'''B','C'部署代码表别名。 – iamdave
@iamdave关于别名,我不使用A,B,C但A代表“活动”,所以是一个众所周知的别名 关于PARTITION BY是否需要,否则当查询运行在某些SQL Server中的多个模式(如2008)时,这些行没有正确排列 – Raffaeu
您能解释一下CTE正在尝试做什么,是您在这里想要完成的目标,这将使我们更好地理解您的代码,目前开始日期和结束日期在您的模式中是相同的表格,你可以请尝试告诉我们你在这里试图完成什么.. – Surendra