Je travaille sur un CTE qui calcule les récurrences d'une semaine mais j'ai quelques problèmes quand le modèle traverse l'année.T-SQL Calculer les récurrences d'une date
Le CTE devrait Calculer toutes les occurrences en fonction des paramètres suivants:
- Récurrence Count - combien de fois il va se passer
- Jours de la semaine - où jour de la semaine, il se produira
- Date de début - lorsque le calcul du modèle va commencer
- Périodicité - Combien de fois en termes de semaines, soit 1 chaque semaine, 2 toutes les 2 semaines
- semaine à partir - Le numéro de la semaine de la première occurrence, ce qui reflète la colonne Date de début
Voici comment je stocke les modèles:
/*
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
);
Voici un couple de motifs que je me sers pour tester mon 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'));
je commence à compter l'examen premier jour de la semaine lundi
SET DATEFIRST 1
Et cela est le CTE j'utilise pour exécuter ce calcul:
/*
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)
Maintenant, si je teste à nouveau mon modèles, par exemple, le premier, je reçois ce résultat, qui a le bug lorsque les occurrences se produisent dans l'année suivante. Le RowNr 15 est faux car il devrait arriver le 23 avril (dimanche) et non la semaine prochaine.
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
Alors que le deuxième modèle est calculé très bien. Je pense que j'ai un problème dans la logique quand le motif traverse l'année et le nombre de semaines remis à 0 en SQL mais je ne trouve pas de solution, j'ai lutté maintenant pour quelques jours.
Vous pouvez exécuter le code avec les exemples here.
En tant que point de référence, vous n'avez pas besoin que 'PARTITION BY' dans votre' ROW_NUMBER' et * * S'il vous plaît ne pas déployer du code avec 'A',' B', 'C' alias de table. – iamdave
@iamdave sur les alias, je n'utilise pas A, B, C mais A signifie "Activités" donc un alias bien connu A propos de PARTITION BY est nécessaire sinon la requête s'exécute sur plusieurs modèles dans certains serveurs SQL comme 2008, les lignes ne sont pas commandées correctement – Raffaeu
Pouvez-vous expliquer ce que le CTE essaie de faire, ce que vous essayez d'accomplir ici, qui nous permettrait de mieux comprendre votre code, actuellement la date de début et la date de fin sont les mêmes table, pouvez-vous s'il vous plaît essayer de nous dire ce que vous essayez d'accomplir ici .. – Surendra