【问题标题】:How to get Previous business day in a week with that of current Business Day using sql server如何使用sql server获取一周中的上一个工作日和当前工作日的工作日
【发布时间】:2012-03-29 09:38:14
【问题描述】:

我有一个在工作日(周一至周五)运行的 ssis 包。如果我在星期二收到文件,背景(DB),它需要前一个工作日日期并进行一些交易。如果我在星期五运行该作业,它必须获取星期一的日期并处理交易。

我已使用以下查询来获取以前的营业日期

Select Convert(varchar(50), Position_ID) as Position_ID,
       TransAmount_Base,
       Insert_Date as InsertDate
  from tblsample
 Where AsOfdate = Dateadd(dd, -1, Convert(datetime, Convert(varchar(10), '03/28/2012', 101), 120))
Order By Position_ID

如果我执行这个查询,我会得到昨天 Transactios 的结果。如果我在星期一运行相同的查询,它必须获取星期五的交易而不是星期日。

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:
    SELECT  DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE()) 
                            WHEN 'Sunday' THEN -2 
                            WHEN 'Monday' THEN -3 
                            ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
    

    比起DATEPART,我更喜欢使用DATENAME 来处理类似的事情,因为它不需要设置DATEFIRST,并确保本地计算机上时间/日期设置的变化不会影响结果。最后DATEDIFF(DAY, 0, GETDATE()) 将删除GETDATE() 的时间部分,无需转换为varchar(慢得多)。


    编辑(将近 2 年)

    这个答案在我的 SO 职业生涯中还很早,每次被点赞都会让我很恼火,因为我不再同意使用 DATENAME 的观点。

    更可靠的解决方案是:

    SELECT  DATEADD(DAY, CASE (DATEPART(WEEKDAY, GETDATE()) + @@DATEFIRST) % 7 
                            WHEN 1 THEN -2 
                            WHEN 2 THEN -3 
                            ELSE -1 
                        END, DATEDIFF(DAY, 0, GETDATE()));
    

    这适用于所有语言和 DATEFIRST 设置。

    【讨论】:

    • 使用DATENAME 来避免需要知道DATEFIRST,但完全忽略它是特定于语言的?
    • 非常好。但是,我遇到的 DATEFIRST 冲突成为问题的场景比语言冲突成为问题的场景更多。例如,如果您要在数据库中创建 UDF,则无法在 UDF 中首先定义日期,您将依赖于调用该函数的查询来设置正确的 datefirst(或不设置不同的 datefirst),这更用户可能需要先设置不同的日期而不是设置不同的语言(根据我的经验)。
    • 更详细地说,我曾经在一家公司工作,佣金周从周三到周二进行纸质销售,周五到周四进行电话销售,我们可以使用相同的查询来报告此问题,方法是设置datefirst 因此,这将使任何使用 DATEPART(DAY, [date]) 来识别周末都没用。这就是我更喜欢使用日期名称的原因。我不主张它是完美无缺的。
    • 嗨,我通过从 AsofDate 列中选择最大日期来对问题进行排序。所以每次都不需要检查前一个工作日是星期五还是其他任何一天。 Select Convert(varchar(50),Position_ID) as Position_ID,TransAmount_Base, Insert_Date as InsertDate from BLE..tblIncome_Staging 其中 AsOfdate = (select max(AsofDate) from tblsample ) Order By Position_ID 这是我实现的逻辑。
    • 为什么最后要写 DATEDIFF(DAY, 0, GETDATE()) 而不是 GETDATE()?
    【解决方案2】:

    此函数返回最后一个工作日,并考虑假期和周末。您需要创建一个简单的假期表。

    -- =============================================
    -- Author:      Dale Kilian
    -- Create date: 2019-04-29
    -- Description: recursive function returns last work day for weekends and 
    -- holidays
    -- =============================================
    ALTER FUNCTION dbo.fnGetWorkWeekday
    (
        @theDate DATE
    )
    RETURNS DATE
    AS
    BEGIN
    
    DECLARE @importDate DATE = @theDate
    DECLARE @returnDate DATE
    --Holidays
    IF EXISTS(SELECT 1 FROM dbo.Holidays WHERE isDeleted = 0 AND @theDate = Holiday_Date)
    BEGIN
    SET @importDate = DATEADD(DAY,-1,@theDate);
    SET @importDate = (SELECT dbo.fnGetWorkWeekday(@importDate))
    END
    --Satruday
    IF(DATEPART(WEEKDAY,@theDate) = 7)
    BEGIN
        SET @importDate = DATEADD(DAY,-1,@theDate);
        SET @importDate = (SELECT dbo.fnGetWorkWeekday(@importDate))
    END
    --Sunday
    IF(DATEPART(WEEKDAY,@theDate) = 1)
    BEGIN
        SET @importDate = DATEADD(DAY,-2,@theDate);
        SET @importDate = (SELECT dbo.fnGetWorkWeekday(@importDate))
    END
    
    
    RETURN @importDate;
    END
    GO
    

    【讨论】:

      【解决方案3】:

      那么怎么样:

      declare @dt datetime='1 dec 2012'
      
      select case when 8-@@DATEFIRST=DATEPART(dw,@dt)  
                  then DATEADD(d,-2,@dt)  
              when (9-@@DATEFIRST)%7=DATEPART(dw,@dt)%7  
                  then DATEADD(d,-3,@dt)  
              else DATEADD(d,-1,@dt)  
          end
      

      【讨论】:

        【解决方案4】:

        查找前一个工作日的最简单解决方案是使用calendar table 和名为IsBusinessDay 的列或类似名称。您的查询是这样的:

        select max(BaseDate)
        from dbo.Calendar c
        where c.IsBusinessDay = 0x1 and c.BaseDate < @InputDate
        

        使用函数的问题在于,当(不是如果)您必须出于任何原因(国定假日等)创建异常时,代码很快就会变得无法维护;使用表格,您只需 UPDATE 一个值。表格还可以更轻松地回答诸如“日期 X 和 Y 之间有多少个工作日”之类的问题,这在报告任务中很常见。

        【讨论】:

          【解决方案5】:

          您可以轻松地将其设为函数调用,添加第二个参数以将 GetDate() 替换为您想要的任何日期。 如果您更改 GetDate(),它将适用于一周中的任何一天、任何日期范围。 如果星期几是输入日期,它不会改变日期(GetDate())

          Declare @DayOfWeek As Integer = 2   -- Monday
          
          Select DateAdd(Day, ((DatePart(dw,GetDate()) + (7 - @DayOfWeek)) * -1) % 7, Convert(Date,GetDate()))
          

          【讨论】:

            【解决方案6】:

            更优雅:

            select DATEADD(DAY, 
            CASE when datepart (dw,Getdate()) < 3 then datepart (dw,Getdate()) * -1 + -1 ELSE -1 END,
            cast(GETDATE() as date))
            

            【讨论】:

              【解决方案7】:
              select  
                dateadd(dd, 
                           case DATEPART(dw, getdate()) 
                           when 1 
                           then -2 
                           when 2 
                           then -3 
                           else -1 
                       end, GETDATE())
              

              【讨论】:

              • 在不知道DATEFIRST 设置的情况下使用DATEPART(dw...ambiguous。不要这样做。
              【解决方案8】:

              感谢上述提示,我的查询略有不同,因为我的用户需要上一个营业日期的所有值。例如,今天是星期一,所以他需要从上周五午夜到周六午夜之间的所有内容。如果有人感兴趣,我使用上述组合和“介于”之间进行了此操作。我不是一个庞大的技术人员。

              -- Declare a variable for the start and end dates.
              declare @StartDate as datetime 
              declare @EndDate as datetime 
              
              SELECT  @StartDate = DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE()) 
              WHEN 'Sunday' THEN -2 
              WHEN 'Monday' THEN -3 
                  ELSE -1 END, DATEDIFF(DAY, 0, GETDATE()))
              select @EndDate = @StartDate + 1 
              select @StartDate , @EndDate 
              -- Later on in the query use "between"
              and mydate between @StartDate and @EndDate
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2018-10-26
                • 1970-01-01
                • 1970-01-01
                • 2014-06-07
                • 1970-01-01
                • 2022-06-10
                • 2015-01-16
                • 1970-01-01
                相关资源
                最近更新 更多