週の反復計算を計算する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
2番目のパターンは正確に計算されますが、私はパターンが年を越えてSQLの0にリセットされたが、解決策を見つけることができないときに論理に問題があると思うので、数日間は苦労しました。
サンプルコードhereを使用してコードを実行することができます。
基準点としては、あなたの 'ROW_NUMBER'にその' PARTITIONのBY'を必要としないと* *はA'、 'B'、 'C' 'でコードを展開しないでくださいテーブルエイリアス。 – iamdave
エイリアスについて@iamdave、私はA、B、Cを使用しませんが、Aは "アクティビティ"を意味しますので、よく知られているエイリアスです 2008年のような特定のSQLサーバで複数のパターンでクエリを実行すると、行が正しく順序付けされていない – Raffaeu
CTEが何をしようとしているのか、ここで達成しようとしていることがわかっていれば、あなたのコードをよりよく理解できるようになります。現在、開始日と終了日はパターンあなたがここで達成しようとしていることを教えてください。 – Surendra