Sql 我从星期一开始数数。而且,当数到周六或周日时,我可以在周五停止数数。所以我写了一个函数,调整开始和结束日期,用7除以周数,再乘以每周5个工作日,然后把剩余的加回去。当我们开始指望一个周末的时候,我确实不得不解释这个问题,但从来没有到过星期一

Sql 我从星期一开始数数。而且,当数到周六或周日时,我可以在周五停止数数。所以我写了一个函数,调整开始和结束日期,用7除以周数,再乘以每周5个工作日,然后把剩余的加回去。当我们开始指望一个周末的时候,我确实不得不解释这个问题,但从来没有到过星期一,sql,sql-server-2008,Sql,Sql Server 2008,--============================================= --作者:托德·佩恩 --创建日期:2018年9月1日 --描述:统计两个日期之间的工作日数 --与DateDiff不同,StartDate和EndDate包含在内 --从1月1日星期一到1月1日星期一返回1 -- ============================================= 创建函数[dbo]。[ufnCountWeekdays] ( --在此处添加函数的参数 @开始日

--============================================= --作者:托德·佩恩 --创建日期:2018年9月1日 --描述:统计两个日期之间的工作日数 --与DateDiff不同,StartDate和EndDate包含在内 --从1月1日星期一到1月1日星期一返回1 -- ============================================= 创建函数[dbo]。[ufnCountWeekdays] ( --在此处添加函数的参数 @开始日期时间, @结束日期日期时间 ) 返回整数 作为 开始 --在这里声明返回变量 声明@CountofWeekDays INT=NULL; 声明@TempDate-DateTime

-- Could CountBackwords 
IF @StartDate > @ENDDate
BEGIN
    SET @TempDate = @StartDate; 
    SET @StartDate = @EndDate;
    SET @EndDate = @TempDate;
END

--Start on Weekend Never get to Monday Case
IF (DatePart(dw,@StartDate) = 7 AND DateDiff(Day,@StartDate,@EndDate) < 2)
OR (DatePart(dw,@StartDate) = 1 AND DateDiff(Day,@StartDate,@EndDate) < 1 )
BEGIN 
    SET @CountOfWeekDays = 0 -- Never got to a WeekDay
END

--NORMAL CASE
ELSE BEGIN 
 -- IF Sat Start just pretend Start Counting on Monday 
 IF (DatePart(dw,@StartDate) = 7) SET @StartDate = dateadd(Day, 2, @StartDate);
 -- IF Sun Start just Start to Counting on Monday 
 IF (DatePart(dw,@StartDate) = 1) SET @StartDate = dateadd(Day, 1, @StartDate);
 -- Sat End just Stop counting on Friday
 IF (DatePart(dw,@EndDate) = 7) SET @EndDate = DateAdd(Day, -1, @EndDate);
 -- Sun END
 if (DatePart(dw,@EndDate) = 1) SET  @EndDate = DateAdd(Day, -2, @EndDate);
 --Find the total number of days we need to count
 Declare @DaysToCount INT = DateDiff(Day,@StartDate, @EndDate)+1; --include start
 -- five days for each full week plus any other weekdays 
 -- remember no worries about starting or ending on weekends
  Set @CountofWeekDays  = Floor(@DaysToCount/7)*5 + (@DaysToCount % 7)

END     

--Check to see if we are counting backwards
IF @TempDate = @EndDate SET @CountofWeekDays = -1 * @CountofWeekDays;

RETURN @CountofWeekDays;
--可以倒计时
如果@StartDate>@ENDDate
开始
设置@TempDate=@StartDate;
设置@StartDate=@EndDate;
设置@EndDate=@TempDate;
结束
--从周末开始从不到周一
IF(DatePart(dw,@StartDate)=7,DateDiff(Day,@StartDate,@EndDate)<2)
或者(DatePart(dw,@StartDate)=1和DateDiff(Day,@StartDate,@EndDate)<1)
开始
设置@CountOfWeekDays=0--从未到达工作日
结束
--正常情况
否则开始
--如果周六开始,就假装周一开始计数
如果(DatePart(dw,@StartDate)=7)设置@StartDate=dateadd(Day,2,@StartDate);
--如果太阳从周一开始计数
如果(DatePart(dw,@StartDate)=1)设置@StartDate=dateadd(Day,1,@StartDate);
--星期五就不算了
如果(DatePart(dw,@EndDate)=7)设置@EndDate=DateAdd(Day,-1,@EndDate);
--太阳端
如果(DatePart(dw,@EndDate)=1)设置@EndDate=DateAdd(Day,-2,@EndDate);
--找到我们需要计算的总天数
声明@DaysToCount INT=DateDiff(Day、@StartDate、@EndDate)+1--包括开始
--每周五天,外加任何其他工作日
--记住不要担心在周末开始或结束
设置@CountofWeekDays=Floor(@DaysToCount/7)*5+(@DaysToCount%7)
结束
--看看我们是否在倒数
如果@TempDate=@EndDate SET@CountofWeekDays=-1*@CountofWeekDays;
返回@countofweekday;
结束 去

快乐编码


托德·佩恩(Todd p Payne)

我认为这不是一个尝试,我有Date1=2013-09-24 19:26:39和Date2=2013-09-26 16:29:31,其中Date1和Date2动态日期我们使用的是包含此类任务的表的所有日期。一般来说,我们链接到该表,如“datestable.date介于startdate和enddate之间”,并仅从dates表中计算日期(记录),其中满足条件(如date为workday)。请参见,但string_val不计算日期string_val计算的是
@d1
@d2
之间的日期,但不是在表中的日期之间(date1和date2),这就是为什么在所有行中都会重复相同的数字。
SELECT  COUNT(*)
FROM    dbo.CalendarTable
WHERE   IsWorkingDay = 1
AND     [Date] > @StartDate
AND     [Date] <= @EndDate;
SET DATEFIRST 1;
DECLARE @StartDate DATETIME = '20131103', 
        @EndDate DATETIME = '20131104';

-- GENERATE A LIST OF ALL DATES BETWEEN THE START DATE AND THE END DATE
WITH AllDates AS
(   SELECT  TOP (DATEDIFF(DAY, @StartDate, @EndDate))
            D = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.Object_ID), @StartDate)
    FROM    sys.all_objects a
            CROSS JOIN sys.all_objects b
)
SELECT  WeekDays = COUNT(*)
FROM    AllDates
WHERE   DATEPART(WEEKDAY, D) NOT IN (6, 7);
SELECT  t.ID,
        t.Date1,
        t.Date2,
        WorkingDays = COUNT(c.DateKey)
FROM    TestTable t
        LEFT JOIN dbo.Calendar c
            ON c.DateKey >= t.Date1
            AND c.DateKey < t.Date2
            AND c.IsWorkingDay = 1
GROUP BY t.ID, t.Date1, t.Date2;
Declare 
    @startdate datetime = '2013-11-01', 
    @enddate datetime = '2013-11-11'


SELECT
   (DATEDIFF(dd, @StartDate, @EndDate) + 1)
  -(DATEDIFF(wk, @StartDate, @EndDate) * 2)
  -(case datepart(dw, @StartDate)+@@datefirst when 8 then 1 else 0 end) 
  -(case datepart(dw, @EndDate)+@@datefirst when 7 then 1 when 14 then 1 else 0 end) 

Returns 7
declare @start_dt as date = '1/1/2009';     -- Date from which the calendar table will be created.
declare @end_dt as date = '1/1/2030';       -- Calendar table will be created up to this date (not including).

create table CalendarTable (
 date_id date primary key,
 date_year smallint,
 date_month tinyint,
 date_day tinyint,
 weekday_id tinyint,
 weekday_nm varchar(10),
 month_nm varchar(10),
 day_of_year smallint,
 quarter_id tinyint,
 first_day_of_month date,
 last_day_of_month date,
 start_dts datetime,
 end_dts datetime,
 week_number_of_month int,
 is_working_day bit,
)

while @start_dt < @end_dt
begin
    insert into CalendarTable(
        date_id, date_year, date_month, date_day, 
        weekday_id, weekday_nm, month_nm, day_of_year, quarter_id, 
        first_day_of_month, last_day_of_month, 
        start_dts, end_dts, week_number_of_month, is_working_day
    )   
    values(
        @start_dt, year(@start_dt), month(@start_dt), day(@start_dt), 
        datepart(weekday, @start_dt), datename(weekday, @start_dt),     datename(month, @start_dt), datepart(dayofyear, @start_dt), datepart(quarter,     @start_dt),
        dateadd(day,-(day(@start_dt)-1),@start_dt), dateadd(day,-(day(dateadd(month,1,@start_dt))),dateadd(month,1,@start_dt)), 
        cast(@start_dt as datetime), dateadd(second,-1,cast(dateadd(day, 1, @start_dt) as datetime)), DATEDIFF(week, DATEADD(MONTH, DATEDIFF(MONTH, 0, @start_dt), 0), @start_dt) +1, 0
    )
    set @start_dt = dateadd(day, 1, @start_dt)
end
GO

-- Set all non-weekend days as business days
update CalendarTable set is_working_day = 1 where weekday_id not in (1,7)
GO

-- New Years Day
update CalendarTable set is_working_day = 0 where date_month = 1 and date_day = 1
GO

-- Memorial Day (last Monday of May)
WITH Memorial_Day AS
(
    SELECT date_id, date_year, date_day,
    ROW_NUMBER() OVER (PARTITION BY date_year ORDER BY date_day desc) AS RowNumber
    FROM CalendarTable
    where date_month = 5 and weekday_id = 2
)   

update CalendarTable set is_working_day = 0 where date_id in (SELECT date_id FROM Memorial_Day 
                                                            where rownumber = 1)
GO

-- Independence Day
update CalendarTable set is_working_day = 0 where date_month = 7 and date_day = 4
GO


-- Labor Day (first Monday in September)
WITH Labor_Day AS
(
    SELECT date_id, date_year, date_day,
    ROW_NUMBER() OVER (PARTITION BY date_year ORDER BY date_day) AS RowNumber
    FROM CalendarTable
    where date_month = 9 and weekday_id = 2
)   

update CalendarTable set is_working_day = 0 where date_id in (SELECT date_id FROM Labor_Day 
                                                            where rownumber = 1)
GO

-- Thanksgiving (fourth Thursday in November)
WITH Thanksgiving AS
(
    SELECT date_id, date_year, date_day,
    ROW_NUMBER() OVER (PARTITION BY date_year ORDER BY date_day) AS RowNumber
    FROM CalendarTable
    where date_month = 11 and weekday_id = 5
)   

update CalendarTable set is_working_day = 0 where date_id in (SELECT date_id FROM Thanksgiving 
                                                            where rownumber = 4)

GO

-- Day After Thanksgiving (fourth Friday in November)
WITH DayAfterThanksgiving AS
(
    SELECT date_id, date_year, date_day,
    ROW_NUMBER() OVER (PARTITION BY date_year ORDER BY date_day) AS RowNumber
    FROM CalendarTable
    where date_month = 11 and weekday_id = 6
)   

update CalendarTable set is_working_day = 0 where date_id in (SELECT date_id FROM DayAfterThanksgiving 
                                                            where rownumber = 4)

GO

-- Christmas Day
update CalendarTable set is_working_day = 0 where date_month = 12 and date_day = 25
GO
-- Could CountBackwords 
IF @StartDate > @ENDDate
BEGIN
    SET @TempDate = @StartDate; 
    SET @StartDate = @EndDate;
    SET @EndDate = @TempDate;
END

--Start on Weekend Never get to Monday Case
IF (DatePart(dw,@StartDate) = 7 AND DateDiff(Day,@StartDate,@EndDate) < 2)
OR (DatePart(dw,@StartDate) = 1 AND DateDiff(Day,@StartDate,@EndDate) < 1 )
BEGIN 
    SET @CountOfWeekDays = 0 -- Never got to a WeekDay
END

--NORMAL CASE
ELSE BEGIN 
 -- IF Sat Start just pretend Start Counting on Monday 
 IF (DatePart(dw,@StartDate) = 7) SET @StartDate = dateadd(Day, 2, @StartDate);
 -- IF Sun Start just Start to Counting on Monday 
 IF (DatePart(dw,@StartDate) = 1) SET @StartDate = dateadd(Day, 1, @StartDate);
 -- Sat End just Stop counting on Friday
 IF (DatePart(dw,@EndDate) = 7) SET @EndDate = DateAdd(Day, -1, @EndDate);
 -- Sun END
 if (DatePart(dw,@EndDate) = 1) SET  @EndDate = DateAdd(Day, -2, @EndDate);
 --Find the total number of days we need to count
 Declare @DaysToCount INT = DateDiff(Day,@StartDate, @EndDate)+1; --include start
 -- five days for each full week plus any other weekdays 
 -- remember no worries about starting or ending on weekends
  Set @CountofWeekDays  = Floor(@DaysToCount/7)*5 + (@DaysToCount % 7)

END     

--Check to see if we are counting backwards
IF @TempDate = @EndDate SET @CountofWeekDays = -1 * @CountofWeekDays;

RETURN @CountofWeekDays;