2016-09-26 73 views
1

我正在嘗試編寫sql查詢來查找過去的第3個工作日,不包括假期和週末。以下是我的方法,但它沒有給出正確的解決方案。請建議SQL Query查找過去的第3個工作日,不包括節假日和週末

第一種方法:

alter function getdate(@givendate datetime) 
returns datetime 
AS 
BEGIN 
declare @calcdate datetime 
declare @reqdate datetime 
declare @count bit 
set @count=1 
select @[email protected]; 
select @[email protected]; 
while(@calcdate<@givendate) 
begin 
while(@count=1) 
begin 
if exists(select 1 from dbo.holidays with(Nolock) where [email protected]) 
begin 
select @[email protected] 
end 
else 
begin 
set @count=0 
end 
end 

select @[email protected]+1 
end 
return @reqdate 
END 

第二種方法:

alter function dbo.getpast3day (@date date) 
returns datetime 
As 
begin 
    declare @reqdate datetime; 
    declare @Newyears_day datetime; 
    declare @Martin_Luther_Kin_Birthday datetime; 
    declare @presidents_day datetime; 
    declare @Memorial_day datetime; 
    declare @Independence_day datetime; 
    declare @Labour_day datetime; 
    declare @Columbus_day datetime; 
    declare @Veterans_day datetime; 
    declare @Thanksgiving_day datetime; 
    declare @Christmas_day datetime; 
    SELECT @reqdate= DATEADD(DAY, CASE (DATEPART(WEEKDAY, @date) + @@DATEFIRST) % 7 
          WHEN 1 THEN -5 
          WHEN 2 THEN -6 
          WHEN 3 THEN -6 
          WHEN 4 THEN -6 
          WHEN 5 THEN -6 
          ELSE -4 
         END, DATEDIFF(DAY, 0, @date)) ; 
[email protected]_Luther_Kin_Birthday      
    begin      
     WITH dates AS (
      SELECT DATEADD(day, number, @date) AS theDate 
      FROM master.dbo.spt_values 
      WHERE type = 'P' 
     ) 
     SELECT @Martin_Luther_Kin_Birthday=theDate 
     FROM dates 
     WHERE DATEDIFF(day, '19000101', theDate) % 7 = 0 
      AND DATEPART(day, thedate)>=15 and DATEPART(day, thedate)<=21 and DATEPART(month,thedate)=1 and datepart(year,thedate)= year(@date); 
    end 
    [email protected]_day 
    begin      
     WITH dates AS (
      SELECT DATEADD(day, number, @date) AS theDate 
      FROM master.dbo.spt_values 
      WHERE type = 'P' 
     ) 
     SELECT @presidents_day=theDate 
     FROM dates 
     WHERE DATEDIFF(day, '19000101', theDate) % 7 = 0 
      AND DATEPART(day, thedate)>=15 and DATEPART(day, thedate)<=21 and DATEPART(month,thedate)=2 and datepart(year,thedate)= year(@date); 
    end 
    [email protected]_day 
    begin      
     WITH dates AS (
      SELECT DATEADD(day, number, @date) AS theDate 
      FROM master.dbo.spt_values 
      WHERE type = 'P' 
     ) 
     SELECT @Memorial_day=theDate 
     FROM dates 
     WHERE DATEDIFF(day, '19000101', theDate) % 7 = 0 
      AND DATEPART(day, thedate)>=22 and DATEPART(day, thedate)<=31 and DATEPART(month,thedate)=2 and datepart(year,thedate)= year(@date); 
    end 
    [email protected]_day 
    begin      
     WITH dates AS (
      SELECT DATEADD(day, number, @date) AS theDate 
      FROM master.dbo.spt_values 
      WHERE type = 'P' 
     ) 
     SELECT @Labour_day=theDate 
     FROM dates 
     WHERE DATEDIFF(day, '19000101', theDate) % 7 = 0 
      AND DATEPART(day, thedate)>=1 and DATEPART(day, thedate)<=7 and DATEPART(month,thedate)=9 and datepart(year,thedate)= year(@date); 
    end 
    [email protected]_day 
    begin      
     WITH dates AS (
      SELECT DATEADD(day, number, @date) AS theDate 
      FROM master.dbo.spt_values 
      WHERE type = 'P' 
     ) 
     SELECT @Columbus_day=theDate 
     FROM dates 
     WHERE DATEDIFF(day, '19000101', theDate) % 7 = 0 
      AND DATEPART(day, thedate)>=8 and DATEPART(day, thedate)<=14 and DATEPART(month,thedate)=10 and datepart(year,thedate)= year(@date); 
    end 
    [email protected]_day 
    begin      
     WITH dates AS (
      SELECT DATEADD(day, number, @date) AS theDate 
      FROM master.dbo.spt_values 
      WHERE type = 'P' 
     ) 
     SELECT @Thanksgiving_day=theDate 
     FROM dates 
     WHERE DATEDIFF(day, '19000101', theDate) % 7 = 0 
      AND DATEPART(day, thedate)>=22 and DATEPART(day, thedate)<=31 and DATEPART(month,thedate)=11 and datepart(year,thedate)= year(@date); 
    end 

    if (@[email protected]Martin_Luther_Kin_Birthday or @[email protected]_day or @[email protected]_day or @[email protected]_day or @[email protected]_day or @[email protected]_day) 
    begin 
     select @reqdate= DATEADD(day,-6,@reqdate) 
    end 

    --RETURN '2216-09-20 00:00:00.000' 


    return @reqdate 

end 

回答

1

對於過去的第3個工作日而言不是100%清楚,但也許這可以提供幫助。顯然,你將不得不決定什麼是假期。

Select [dbo].[SomeFunctionName]('2016-01-20',3) 

返回

2016-01-15 

自定義功能:

CREATE FUNCTION [dbo].[SomeFunctionName](@Date date,@nDay int) 
Returns Date 
As 
Begin 
Declare @RetVal Date 

;with cteHolidays as (
    Select * from (Values 
     ('2016-01-01','New Year''s Day'), 
     ('2016-01-18','Martin Luther King, Jr,'), 
     ('2016-02-15','Washington''s Birthday'), 
     ('2016-03-25','Good Friday'), 
     ('2016-05-30','Memorial Day'), 
     ('2016-07-04','Independence Day'), 
     ('2016-09-05','Labor Day'), 
     ('2016-11-24','Thanksgiving'), 
     ('2016-11-25','Black Friday'), 
     ('2016-12-26','Christmas Day') 
     ) as Holidays (Date,Name) 
), cteDays as (
Select * 
     ,RowNr = Row_Number() over (Order By RetVal Desc) 
From [dbo].[udf-Create-Range-Date](DateAdd(DD,-3*@nDay,@Date),@Date,'DD',1) 
Where RetVal not in (Select Date from cteHolidays) 
    and DatePart(DW,RetVal) between 2 and 6 
) 
Select @RetVal=RetVal 
From cteDays 
Where [email protected] 

Return @RetVal 

End 

它確實需要,我用它來創建動態數據的通用輔助函數範圍

的輔助函數

CREATE FUNCTION [dbo].[udf-Create-Range-Date] (@DateFrom datetime,@DateTo datetime,@DatePart varchar(10),@Incr int) 

Returns 
@ReturnVal Table (RetVal datetime) 

As 
Begin 
    With DateTable As (
     Select DateFrom = @DateFrom 
     Union All 
     Select Case @DatePart 
       When 'YY' then DateAdd(YY, @Incr, df.dateFrom) 
       When 'QQ' then DateAdd(QQ, @Incr, df.dateFrom) 
       When 'MM' then DateAdd(MM, @Incr, df.dateFrom) 
       When 'WK' then DateAdd(WK, @Incr, df.dateFrom) 
       When 'DD' then DateAdd(DD, @Incr, df.dateFrom) 
       When 'HH' then DateAdd(HH, @Incr, df.dateFrom) 
       When 'MI' then DateAdd(MI, @Incr, df.dateFrom) 
       When 'SS' then DateAdd(SS, @Incr, df.dateFrom) 
       End 
     From DateTable DF 
     Where DF.DateFrom < @DateTo 
    ) 

    Insert into @ReturnVal(RetVal) Select DateFrom From DateTable option (maxrecursion 32767) 

    Return 
End 

-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2020-10-01','YY',1) 
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2020-10-01','DD',1) 
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2016-10-31','MI',15) 
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2016-10-02','SS',1) 

EDIT

爲了驗證上述

Date  Weekday  BusDayNr 
2016-01-20 Wednesday 1  << Selected Date 
2016-01-19 Tuesday  2 
2016-01-18 Monday  -  << Holiday Martin Luther King, Jr 
2016-01-17 Sunday  - 
2016-01-16 Saturday  - 
2016-01-15 Friday  3  << Date Returned 
2016-01-14 Thursday 
2016-01-13 Wednesday 
2016-01-12 Tuesday 
2016-01-11 Monday 
列出的示例
0

這裏是另一種方法: 如果你推杆週末和節假日到1個這樣的事情應該工作:

declare @holidays_weekends table (
dates date) 

insert into @holidays_weekends 
values('2016-09-23'), 
('2016-09-24'), 
('2016-09-25') 


declare 
@date date = getdate() 

select dateadd("dd", -3 -(
select count(*) 
from @holidays_weekends 
where dates in( 
dateadd("dd",-1,@date), 
dateadd("dd",-2,@date), 
dateadd("dd",-3,@date), 
dateadd("dd",-4,@date), 
dateadd("dd",-5,@date), 
dateadd("dd",-6,@date), 
dateadd("dd",-7,@date))) ,@date) as '3rd_day' 
相關問題