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