T-SQL CTE,计算上一行值

T-SQL CTE, calculation on Previous Row value

我有一个 CTE returns 一组行取决于以下方式的模式:

模式Table从开始日期开始为下周一创建 100 行)

|                                        |
|--Id--|--Start Date--|--Count--|--Days--|
|                                        |
|--AB--|  01-01-2000  |   100   | Monday |
|                                        |

而且我有一个 函数,它通过如下传递开始日期来计算下一个 发生的日期

dbo.fx_get_next_occurrence(@startDate DATETIME, @days VARCHAR)

为了生成行,我使用 CTE 如下:

WITH Occurrences_CTE(Num, Id, StartDate)
AS
(
    SELECT
        SP.n
        ,F.Id
        ,dbo.fx_get_next_occurrence(F.Days, F.StartDate)
    FROM
        #RecurrencePattern AS F 
        INNER JOIN
        dbo.Numbers AS SP
        ON SP.n between 1 and F.[Count]
)

dbo.numbers 是一个包含递增数字列表的 table。

现在,当我 运行 SELECT 当然 CTE returns 总是相同 "next date" 因为日期永远不会增加,所以这个 SELECT:

SELECT 
    CTE.Id, CTE.Num, CTE.StartDate
FROM 
    Occurrences_CTE CTE

生成如下结果:

|                             |
|--Id--|--Num--|--Start Date--|
|                             |
|--AB--|--001--|--01-03-2000--|
|--AB--|--002--|--01-03-2000--|
|--AB--|--003--|--01-03-2000--|
|--AB--|--004--|--01-03-2000--|
|--AB--|--005--|--01-03-2000--|

现在,尽管 函数 按预期工作,我如何从 CTE 获得 先前计算的日期行 以便我可以将此日期传递给我的功能以从前一天开始移至下一个可用日期吗?加入 CTE 本身,然后呢?

我在 SQL 2012 年和 2014 年,所以我可以使用 LAG 和其他功能。

也许你可以稍微简化一下。

我无法与您的 UDF 通话,但您可能很快就会看到,这可能没有必要。 cteKeyDate 产生的内容超出了需要,但当您加入数据时会过滤结果。

您可能还注意到我在周一和周五的样本数据中添加了另一行,但计数仅为 50

Declare @Table table (id varchar(25),StartDate Date,Count int,Days varchar(25))
Insert into @Table values
('AB','2000-01-01',100,'Monday'),
('CD','2000-01-01',50,'Monday,Friday')


Declare @MinDate Date = (Select min(StartDate) from @Table)
Declare @MaxCntr Int  = (Select max(Count) from @Table)
Declare @MaxDate Date = DateAdd(wk,@MaxCntr+10,@MinDate)

;With cteKeyDate As (
    Select KeyDate = @MinDate,KeyDOW = DateName(WEEKDAY,@MinDate)
    Union All
    Select KeyDate =  DateAdd(DD, 1, df.KeyDate) ,KeyDOW = DateName(WEEKDAY,DateAdd(DD, 1, df.KeyDate))
    From cteKeyDate DF
    Where DF.KeyDate <= @MaxDate
) 
Select * 
 From (
        Select A.ID
              ,A.StartDate
              ,A.Count
              ,A.Days 
              ,KeyDate
              ,KeyDow
              ,RowNr = Row_Number() over (Partition By A.ID Order By B.KeyDate)
         from @Table A
         Join cteKeyDate B on B.KeyDate>=A.StartDate and Charindex(KeyDOW,Days)>0 
      ) Final
 Where RowNr<=Count
 Option (maxrecursion 32767)

Returns -- 我展示了所有字段以便您更好地可视化结果

ID  StartDate   Count   Days            KeyDate     KeyDow  RowNr
AB  2000-01-01  100     Monday          2000-01-03  Monday  1
AB  2000-01-01  100     Monday          2000-01-10  Monday  2
AB  2000-01-01  100     Monday          2000-01-17  Monday  3
AB  2000-01-01  100     Monday          2000-01-24  Monday  4
... 
AB  2000-01-01  100     Monday          2001-11-05  Monday  97
AB  2000-01-01  100     Monday          2001-11-12  Monday  98
AB  2000-01-01  100     Monday          2001-11-19  Monday  99
AB  2000-01-01  100     Monday          2001-11-26  Monday  100
CD  2000-01-01  50      Monday,Friday   2000-01-03  Monday  1
CD  2000-01-01  50      Monday,Friday   2000-01-07  Friday  2
CD  2000-01-01  50      Monday,Friday   2000-01-10  Monday  3
.....
CD  2000-01-01  50      Monday,Friday   2000-06-16  Friday  48
CD  2000-01-01  50      Monday,Friday   2000-06-19  Monday  49
CD  2000-01-01  50      Monday,Friday   2000-06-23  Friday  50

为每个添加了一个字段。所以 1 = 每周,2 是每隔一周,依此类推。

试一试

Declare @Table table (id varchar(25),StartDate Date,Count int,Days varchar(25),Every int)
Insert into @Table values
('AB','2000-01-01',50,'Monday',2),
('CD','2000-01-01',50,'Monday,Friday',2)


Declare @MinDate Date = (Select min(StartDate) from @Table)
Declare @MaxCntr Int  = (Select max(Count) from @Table)
Declare @MaxDate Date = DateAdd(wk,@MaxCntr+10,@MinDate)

;With cteKeyDate As (
    Select KeyDate = @MinDate,KeyDOW = DateName(WEEKDAY,@MinDate),KeyWeek = datepart(WK,@MinDate)
    Union All
    Select KeyDate =  DateAdd(DD, 1, df.KeyDate) ,KeyDOW = DateName(WEEKDAY,DateAdd(DD, 1, df.KeyDate)), KeyWeek= DatePart(WK,DateAdd(DD, 1, df.KeyDate))
    From cteKeyDate DF
    Where DF.KeyDate <= @MaxDate
) 
Select * 
 From (
        Select A.ID
              ,A.StartDate
              ,A.Count
              ,A.Days 
              ,A.Every
              ,KeyDate
              ,KeyDow
              ,KeyWeek
              ,RowNr = Row_Number() over (Partition By A.ID Order By B.KeyDate)
         from @Table A
         Join cteKeyDate B on B.KeyDate>=A.StartDate and Charindex(KeyDOW,Days)>0 
      ) Final
 Where RowNr<=Count and (KeyWeek) % (Every) = 0 
 Option (maxrecursion 32767)