【问题标题】:DAYOFWEEK inside whileDAYOFWEEK 里面 while
【发布时间】:2015-10-15 14:32:49
【问题描述】:

过去一个小时我一直在研究这个问题,但似乎无法让它发挥作用。 我需要做的就是插入这些值,但我需要跳过包含星期六或星期日的插入。

Begin Tran

Declare @VaccID int = 26
Declare @Clinic int = 36
Declare @Enroll int = 30
Declare @SignUp int = 0
Declare @BlnAct int = 1
Declare @BlnDis int = 1
Declare @DateStartTime datetime =  '2015-09-16 11:00:00.000'
Declare @DateEndTime datetime = '2015-09-16 14:00:00.000'
Declare @EndDate date = '2015-10-16'
Declare @Days int = DATEDIFF(dd, @DateStartTime, @EndDate) 


Select @DateStartTime, @DateEndTime, @Days

Declare @i int = 0
Declare @WeekDay varchar = ''

WHILE @i <= @Days

IF(@WeekDay = 'Monday' OR 
   @WeekDay = 'Tuesday' OR 
   @WeekDay = 'Wednesday' OR 
   @WeekDay = 'Thursday' OR 
   @WeekDay = 'Friday')

Begin

INSERT INTO dbo.tblSessions 
           ([intVaccID],
            [intLocationID],
            [dtDateTimeStart],
            [dtDateTimeStop],
            [intEnrollmentMax],
            [intSignedUp],
            [blnActive],
            [blnDisplay])

Values (@VaccID, 
        @Clinic, 
        DATEADD(dd, @i, @DateStartTime), 
        DATEADD(dd, @i, @DateEndTime), 
        @Enroll, 
        @SignUp, 
        @BlnAct, 
        @BlnDis) 

SELECT @VaccID as intVaccID, 
       @Clinic as intLocationID, 
       DATEADD(dd, @i, @DateStartTime) as dtDateTimeStart, 
       DATEADD(dd, @i, @DateEndTime) as dtDateTimeStop, 
       @Enroll as intEnrollmentMax, 
       @SignUp as intSignedUp, 
       @BlnAct as blnActive, 
       @BlnDis as blnDisplay

SET @i = @i + 1
SET @WeekDay = DAYOFWEEK(dw, DATEADD(dd, @i, @DateStartTime))


END

Rollback Tran

Commit Tran

它至少在一周中的每一天都在填写,但现在似乎正在暂停查询。我知道我错过了一些可笑的小东西,但我似乎无法找到它。我想这是我今天的白鲸。

【问题讨论】:

  • 嗯,你的“如果”错了吗?因为@weekday 被声明为''所以工作日永远不会是星期五或星期四等

标签: sql-server while-loop dayofweek


【解决方案1】:

您应该将其作为基于集合的操作来执行,而不是使用循环。使用计数表时无需循环。看看这是否不会产生所需的输出。

Declare @VaccID int = 26
    , @Clinic int = 36
    , @Enroll int = 30
    , @SignUp int = 0
    , @BlnAct int = 1
    , @BlnDis int = 1
    , @DateStartTime datetime =  '2015-09-16 11:00:00.000'
    , @DateEndTime datetime = '2015-09-16 14:00:00.000'
    , @EndDate date = '2015-10-16';

WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 FROM E4
    )

select @VaccID
    , @Clinic
    , DATEADD(dd, t.N, @DateStartTime)
    , DATEADD(dd, t.N, @DateEndTime)
    , @Enroll
    , @SignUp
    , @BlnAct
    , @BlnDis
from cteTally t
where t.N < = DATEDIFF(day, @DateStartTime, @EndDate)
and DATENAME(weekday, DATEADD(dd, t.N, @DateStartTime)) not in ('Saturday', 'Sunday');

【讨论】:

  • 糟糕,我忘了排除周六和周日...一分钟
  • 很抱歉。现在它将排除周六和周日。 :)
  • 感谢基于集合的方法。感谢您的解决方案。
【解决方案2】:

@JBBeginner:更正您的查询,

Begin Tran

Declare @VaccID int = 26
Declare @Clinic int = 36
Declare @Enroll int = 30
Declare @SignUp int = 0
Declare @BlnAct int = 1
Declare @BlnDis int = 1
Declare @DateStartTime datetime =  '2015-09-16 11:00:00.000'
Declare @DateEndTime datetime = '2015-09-16 14:00:00.000'
Declare @EndDate date = '2015-10-16'
Declare @Days int = DATEDIFF(dd, @DateStartTime, @EndDate) 


Select @DateStartTime, @DateEndTime, @Days

Declare @i int = 0
Declare @WeekDay varchar = DAYOFWEEK(dw, @DateStartTime) -- changed

WHILE @i <= @Days
Begin                                                    -- changed

IF(@WeekDay = 'Monday' OR 
   @WeekDay = 'Tuesday' OR 
   @WeekDay = 'Wednesday' OR 
   @WeekDay = 'Thursday' OR 
   @WeekDay = 'Friday')

Begin

INSERT INTO dbo.tblSessions 
           ([intVaccID],
            [intLocationID],
            [dtDateTimeStart],
            [dtDateTimeStop],
            [intEnrollmentMax],
            [intSignedUp],
            [blnActive],
            [blnDisplay])

Values (@VaccID, 
        @Clinic, 
        DATEADD(dd, @i, @DateStartTime), 
        DATEADD(dd, @i, @DateEndTime), 
        @Enroll, 
        @SignUp, 
        @BlnAct, 
        @BlnDis) 

SELECT @VaccID as intVaccID, 
       @Clinic as intLocationID, 
       DATEADD(dd, @i, @DateStartTime) as dtDateTimeStart, 
       DATEADD(dd, @i, @DateEndTime) as dtDateTimeStop, 
       @Enroll as intEnrollmentMax, 
       @SignUp as intSignedUp, 
       @BlnAct as blnActive, 
       @BlnDis as blnDisplay

SET @i = @i + 1
SET @WeekDay = DAYOFWEEK(dw, DATEADD(dd, @i, @DateStartTime))

END

END                                                          -- changed

--Rollback Tran                                              -- changed

Commit Tran

【讨论】:

    【解决方案3】:

    递归 CTE 也适用于日期:

        Declare @DateStartTime datetime =  '2015-09-16 11:00:00.000'
        Declare @DateEndTime datetime = '2015-09-16 14:00:00.000'
        Declare @EndDate date = '2015-10-16'
    
        ;WITH cteDates AS (
                SELECT @DateStartTime AS StartDate, @DateEndTime AS EndDate, DATENAME(weekday, @DateStartTime) AS NameOfDay
                UNION ALL
                SELECT DATEADD(day, 1, cteDates.StartDate), DATEADD(day, 1, cteDates.EndDate), DATENAME(weekday, DATEADD(day, 1, cteDates.StartDate)) AS NameOfDay
                FROM cteDates
                WHERE DATEADD(day, 1, cteDates.StartDate) <= '2015-10-16'
        )
        -- INSERT INTO dbo.tblSessions ( ...)  -- Omitted for clarity
        SELECT * FROM cteDates
        WHERE NameOfDay NOT IN ('Saturday', 'Sunday')
    

    【讨论】:

      【解决方案4】:

      为什么不使用 GOTO 关键字跳过星期六和星期日:

      实际上您的查询应该以其他方式重构。但是对于上述情况,您可以使用它。

      WHILE @i< @days
      BEGIN
      
      
      LABEL :
      SET @i = @i + 1
      SET @WeekDay = DAYOFWEEK(dw, DATEADD(dd, @i, @DateStartTime))
      
      IF(@WeekDay = 'SATURDAY' OR @WeekDay = 'SUNDAY')
      GOTO LABEL 
      
      END
      

      【讨论】:

      • 最好使用基于集合的方法,然后忘记像 GOTO 这样可怕的东西甚至存在。
      猜你喜欢
      • 2012-05-27
      • 2013-03-10
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 2020-03-07
      • 1970-01-01
      • 2019-01-13
      • 2015-11-02
      相关资源
      最近更新 更多