SQL-从日期减去工作日

时间:2019-09-06 16:50:11

标签: sql sql-server dateadd

我正在尝试查询我的表以查找日期字段在10个工作日前与今天之间的记录。我正在努力计算10个工作日前的日期。

就我而言,假期并不重要。无论假期/工作日如何,我都只需要包括周一至周五。

我发现此SQL代码可以执行我想要的操作,但是倒退了。这将计算两个日期之间的工作日数,我需要减去一个数字并得出一个日期。

DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = '2019-08-26'
SET @EndDate = GETDATE()

SELECT
   (DATEDIFF(dd, @StartDate, @EndDate) + 1)
  -(DATEDIFF(wk, @StartDate, @EndDate) * 2)
  -(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
  -(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)

我尝试使用DATEADD,但无法找出排除周六和周日的任何逻辑。我也不想使用某个函数,因为我绝对不需要。没有每天循环的功能,我无法在线找到有关DATEADD的任何信息。

所需功能:

START DATE: TODAY / GETDATE()
NUMBER OF BUSINESS DAYS: 10

DATEADD(DAY, -10 + CALULATE WEEKEND DAYS?, GETDATE())

2 个答案:

答案 0 :(得分:0)

尝试如下所示的递归CTE-

DECLARE @start_date DATE= GETDATE(), 
    @NumberOfDays INT= 10;


WITH cte
AS 
(               
    SELECT @start_date AS date_

    UNION ALL

    SELECT CAST(DATEADD(day, -1, date_) AS DATE)
    FROM cte
    WHERE date_ >= DATEADD(
        DD,
        -(@NumberOfDays   + (@NumberOfDays/7+1)*3), 
        --Generating a approximate number consediring  
        --Number Of Business Day + Approximate Week Ends for that days
        @start_date
    )
),
CTE2 AS
(
    SELECT Date_,ROW_NUMBER() OVER (ORDER BY Date_ DESC) RN
    FROM cte 
    WHERE DATENAME(dw, Date_) NOT IN ('Saturday','Sunday')
)

SELECT Date_ 
FROM CTE2
WHERE  RN = @NumberOfDays
OPTION(MAXRECURSION 0)

答案 1 :(得分:0)

由于您只关心周末,而不关心其他假期,因此很容易使用每个日历周(7天)中有5个工作日来计算工作日中的日历天数。如果您可以使用标量函数,则可以使用以下命令:

CREATE FUNCTION SubBusinessDays(
    @days int,
    @date datetime
) RETURNS int
BEGIN

    SET @days = @days-1; -- number of days are inclusive of the start date

    SET @date = DATEADD(DAY, -(@days / 5 * 7 + @days % 5),
                    DATEADD(DAY, (CASE (DATEPART(WEEKDAY, @date) + @@DATEFIRST) % 7 
                                      WHEN 0 THEN -1 
                                      WHEN 1 THEN -2 
                                      ELSE 0 END), @date));
    RETURN DATEADD(DAY, (CASE WHEN (DATEPART(WEEKDAY, @date) + @@DATEFIRST) % 7 IN (0, 1) 
                              THEN -2 ELSE 0 END), @date);
END

另一方面,如果您需要处理表,则可以使用CROSS APPLY来执行以下示例中的步骤:

DECLARE @t TABLE(StartDate Datetime, BDays int)

INSERT INTO @t
SELECT d, ofs
FROM (VALUES ('20190906'), ('20190907'), ('20190908'), ('20190909'), ('20190910')) AS sd(d)
    CROSS JOIN 
     (VALUES (7), (8), (9), (10), (11)) AS bd(ofs)


SELECT StartDate, BDays, EndDate
FROM @t
    CROSS APPLY (SELECT BDaysMinus1 = BDays-1) x1
    CROSS APPLY (SELECT EndDateTemp = DATEADD(DAY, -((BDaysMinus1 / 5) * 7 + BDaysMinus1 % 5),
                    DATEADD(DAY, (CASE (DATEPART(WEEKDAY, StartDate) + @@DATEFIRST) % 7  
                                        WHEN 0 THEN -1 
                                        WHEN 1 THEN -2 
                                        ELSE 0 END), StartDate))) x2
    CROSS APPLY (SELECT EndDate = DATEADD(DAY, (CASE WHEN (DATEPART(WEEKDAY, EndDateTemp) + @@DATEFIRST) % 7 IN (0,1) 
                                        THEN -2 ELSE 0 END), EndDateTemp)) x3