2017-03-04 75 views
0

我有一个现有的存储过程,我用它来获取我的数据库系统的可用预订。我目前通过属性显示当前日期以显示特定日期的所有预订。我想要做的是将日期范围(使用CTE)作为查询的“日期”部分,以便我可以在完整范围内获取所有预订,而不仅仅是一天。转换存储过程使用日期CTE而不是单一日期

下面是我现有的存储过程:正如你可以在下面看到的,我在我的select语句(和子查询)中使用@CurrentDay属性。我如何使用CTE(在帖子的底部),基本上“为每个”而不是使用当前传入的日期?

  ALTER PROCEDURE [dbo].[GetUpcomingTrialSlots] 
       @LocationId int, 
       @CurrentDateTime datetime 
      AS 
      BEGIN 


      declare @CurrentDay Date 

      declare @WindowTimeStart DateTime 

      set datefirst 1 
      select @CurrentDay = CONVERT(date, @CurrentDateTime) 
      select @WindowTimeStart = CONVERT(time,@CurrentDateTime) 

      -- Day One 
      SELECT * FROM 
      (
      select ts.id TimeSlotId, 
        @locationId LocationId, 
        @CurrentDay BookingDay, 
        datename(dw,DATEPART(dw, @CurrentDay)-1) DayOfWeek, 
        ts.StartTime, 
        COALESCE(
         (select top 1 AvailableSlots 
           FROM TrialTimeBlockOverride 
           where CONVERT(datetime, CAST(@CurrentDay AS DATETIME) + CAST(ts.EndTime AS DATETIME)) 
           between 
           CONVERT(datetime, CAST(OverrideStartDate AS DATETIME) + CAST(AltOpenTime AS DATETIME)) 
           and 
           CONVERT(datetime, CAST(OverrideEndDate AS DATETIME) + CAST(AltCloseTime AS DATETIME))  
           and 
           LocationId = @LocationId   
         ) 
        , 
         (select top 1 AvailableSlots from TrialTimeBlock where DayOfWeek = DATEPART(dw, @CurrentDay) 
           and ts.StartTime >= starttime and ts.StartTime < endtime and LocationId = @LocationId)    
        ) as AvailableSlots, 
        ts.EndTime, 
       case 
        when 
         EXISTS (select * from TrialTimeBlock where ts.StartTime >= StartTime and ts.StartTime < EndTime and LocationId = @LocationId and DayOfWeek = datepart(dw, @CurrentDay)) THEN CAST(1 AS BIT) 
        else CAST(0 AS BIT) 
       end as TrialSlot, 
       case 
        when 
         EXISTS (
         SELECT * 
          FROM TrialTimeBlockOverride 
          where CONVERT(datetime, CAST(@CurrentDay AS DATETIME) + CAST(ts.StartTime AS DATETIME)) 
          >= 
          CONVERT(datetime, CAST(OverrideStartDate AS DATETIME) + CAST(AltOpenTime AS DATETIME)) 
          and 
          CONVERT(datetime, CAST(@CurrentDay AS DATETIME) + CAST(ts.StartTime AS DATETIME)) 
          < 
          CONVERT(datetime, CAST(OverrideEndDate AS DATETIME) + CAST(AltCloseTime AS DATETIME))  
          and 
          LocationId = @LocationId 
          and 
          AvailableSlots = 0 
         ) THEN 0 /*This doesn't seem right to me */ 
        else 1 
       end as [TrialTimeAvailable], 
       case 
        when 
         EXISTS (
         SELECT * 
         FROM OpeningHourOverride 
         where CONVERT(datetime, CAST(@CurrentDay AS DATETIME) + CAST(ts.StartTime AS DATETIME)) 
         >= 
         CONVERT(datetime, CAST(OverrideStartDate AS DATETIME) + CAST(AltOpenTime AS DATETIME))    
         and 
         CONVERT(datetime, CAST(@CurrentDay AS DATETIME) + CAST(ts.StartTime AS DATETIME)) 
         < 
         CONVERT(datetime, CAST(OverrideEndDate AS DATETIME) + CAST(AltCloseTime AS DATETIME))  
         and 
         LocationId = @LocationId 
         and 
         AvailableSlots = 0 
         ) THEN 'Closed' /*This doesn't seem right to me */ 
        else 'Open' 
       end as [OpenStatus], 
       case 
        when 
         (select count(*) from InitialAssessment where LocationId = @LocationId and TimeSlotId = ts.Id and AssessmentDate = @CurrentDay) > 1 THEN 'true' 
        else 'false' 
       end as HasAssessment, 
       (select count(*) from InitialAssessment where LocationId = @LocationId and TimeSlotId = ts.Id and AssessmentDate = @CurrentDay and IsFriendRecommendation is null) as AssessmentCount, 
       case 
        when 
         EXISTS (
         SELECT * 
         FROM OpeningHourOverride 
         where CONVERT(datetime, CAST(@CurrentDay AS DATETIME) + CAST(ts.StartTime AS DATETIME)) 
         >= 
         CONVERT(datetime, CAST(OverrideStartDate AS DATETIME) + CAST(AltOpenTime AS DATETIME))    
         and 
         CONVERT(datetime, CAST(@CurrentDay AS DATETIME) + CAST(ts.StartTime AS DATETIME)) 
         < 
         CONVERT(datetime, CAST(OverrideEndDate AS DATETIME) + CAST(AltCloseTime AS DATETIME))  
         and 
         LocationId = @LocationId 
         ) THEN 
         (SELECT OverrideReason 
         FROM OpeningHourOverride 
         where CONVERT(datetime, CAST(@CurrentDay AS DATETIME) + CAST(ts.StartTime AS DATETIME)) 
         >= 
         CONVERT(datetime, CAST(OverrideStartDate AS DATETIME) + CAST(AltOpenTime AS DATETIME))    
         and 
         CONVERT(datetime, CAST(@CurrentDay AS DATETIME) + CAST(ts.StartTime AS DATETIME)) 
         < 
         CONVERT(datetime, CAST(OverrideEndDate AS DATETIME) + CAST(AltCloseTime AS DATETIME))  
         and 
         LocationId = @LocationId) 

          /*This doesn't seem right to me */ 
        else '' 
       end as ClosureReason 

      from Timeslot ts 
      left join OpeningHour oh 
       on @locationId = oh.LocationId 
       and oh.DayOfWeek = DATEPART(dw, @CurrentDay) 
      where ts.StartTime >= oh.OpenTime 
      and  ts.EndTime < oh.CloseTime 
      and  datepart(minute,ts.StartTime) = 0 
      and  CAST(ts.StartTime as DateTime) > @WindowTimeStart 

      ) T WHERE TrialSlot = 1 
      AND AssessmentCount <AvailableSlots 
      And OpenStatus = 'Open' 
      AND TrialTimeAvailable = 1 
      order by 
      BookingDay, 
      StartTime 


      END 

CTE例如SQL

declare @StartDate date = '2017-01-01' 
declare @EndDate date = '2017-01-10' 

;WITH cte AS (
    SELECT @StartDate AS TrialDate 
    UNION ALL 
    SELECT DATEADD(day,1,TrialDate) as currentDate 
    FROM cte 
    WHERE DATEADD(day,1,TrialDate) <= @EndDate 
) 

回答

2

两个快速选择:

选项1 - 特设理货表

Declare @Date1 date = '2017-01-01' 
Declare @Date2 date = '2017-01-10' 
Select Top (DateDiff(DD,@Date1,@Date2)+1) D=DateAdd(DD,-1+Row_Number() Over (Order By Number),@Date1) From master..spt_values 

返回

D 
2017-01-01 
2017-01-02 
2017-01-03 
2017-01-04 
2017-01-05 
2017-01-06 
2017-01-07 
2017-01-08 
2017-01-09 
2017-01-10 

选项2:表值用功能

提供了一些更多的选项:用户提供的日期/时间范围,日期部分和增量,并且速度更快,所述CTE。也很容易纳入子查询和/或CROSS APPLY。

Declare @Date1 date = '2017-01-01' 
Declare @Date2 date = '2017-01-10' 
Select * from [dbo].[udf-Range-Date](@Date1,@Date2,'DD',1) 

返回

RetSeq RetVal 
1  2017-01-01 00:00:00.000 
2  2017-01-02 00:00:00.000 
3  2017-01-03 00:00:00.000 
4  2017-01-04 00:00:00.000 
5  2017-01-05 00:00:00.000 
6  2017-01-06 00:00:00.000 
7  2017-01-07 00:00:00.000 
8  2017-01-08 00:00:00.000 
9  2017-01-09 00:00:00.000 
10  2017-01-10 00:00:00.000 

的UDF如果有兴趣

CREATE FUNCTION [dbo].[udf-Range-Date] (@R1 datetime,@R2 datetime,@Part varchar(10),@Incr int) 
Returns Table 
Return (
    with cte0(M) As (Select 1+Case @Part When 'YY' then DateDiff(YY,@R1,@R2)/@Incr When 'QQ' then DateDiff(QQ,@R1,@R2)/@Incr When 'MM' then DateDiff(MM,@R1,@R2)/@Incr When 'WK' then DateDiff(WK,@R1,@R2)/@Incr When 'DD' then DateDiff(DD,@R1,@R2)/@Incr When 'HH' then DateDiff(HH,@R1,@R2)/@Incr When 'MI' then DateDiff(MI,@R1,@R2)/@Incr When 'SS' then DateDiff(SS,@R1,@R2)/@Incr End), 
     cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)), 
     cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h), 
     cte3(N,D) As (Select 0,@R1 Union All Select N,Case @Part When 'YY' then DateAdd(YY, N*@Incr, @R1) When 'QQ' then DateAdd(QQ, N*@Incr, @R1) When 'MM' then DateAdd(MM, N*@Incr, @R1) When 'WK' then DateAdd(WK, N*@Incr, @R1) When 'DD' then DateAdd(DD, N*@Incr, @R1) When 'HH' then DateAdd(HH, N*@Incr, @R1) When 'MI' then DateAdd(MI, N*@Incr, @R1) When 'SS' then DateAdd(SS, N*@Incr, @R1) End From cte2) 

    Select RetSeq = N+1 
      ,RetVal = D 
    From cte3,cte0 
    Where D<[email protected] 
) 
/* 
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS 
Syntax: 
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1) 
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1) 
*/ 
+0

感谢这个... SOR如果我不是100%清楚..我可以创建CTE没有问题,问题是我如何采取该CTE并将其应用于我目前只使用一个日期的查询? –

+0

@ChristopherPettigrew你是否希望运行你的存储过程N次?如果是这样,请将其转换为TVF并通过CROSS APPLY进行调用 –

0

假设您可以将存储过程转换为TVF

Declare @Date1 date = '2017-01-01' 
Declare @Date2 date = '2017-01-10' 
Declare @LocationId int = 1 

Select A.D -- << Optional 
     ,B.* 
From (Select Top (DateDiff(DD,@Date1,@Date2)+1) D=DateAdd(DD,-1+Row_Number() Over (Order By Number),@Date1) From master..spt_values) A 
Cross Apply ( 
       Select * 
       From [dbo].[tvf_GetUpcomingTrialSlots](@LocationId,A.D) 
       Order By BookingDay,StartTime  
      ) B