2013-11-04 110 views
1

如何計算SQL Server 2008中從表(從第1行到結尾)的兩個日期之間的工作天數?在SQL Server中計算排除週末(週一到週五)的天數

我想這樣的事情,但它不工作

DECLARE @StartDate as DATETIME, @EndDate as DATETIME 

Select @StartDate = date2 from testtable ; 
select @EndDate = date1 from testtable ; 

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) 
+0

http://stackoverflow.com/questions/1803987/how-do-i-exclude-weekend-days-in-a-sql-server-query – arjen1984

+0

認爲那不試試,我有日期1 = 2013-09-24 19:26:39和Date2 = 2013-09-26 16:29:31其中Date1和Date2動態日期 – user2943856

+0

我們正在使用包含此類任務的表的所有日期。通常,我們鏈接到此表,如「datestable.date之間的startdate和enddate」,並只計算日期表中的日期(記錄),其中條件(如日期是工作日)得到滿足。 – Arvo

回答

5

我總是建議Calendar table,那麼你可以簡單地使用:

SELECT COUNT(*) 
FROM dbo.CalendarTable 
WHERE IsWorkingDay = 1 
AND  [Date] > @StartDate 
AND  [Date] <= @EndDate; 

由於SQL沒有節假日的知識例如兩個日期之間的工作日數並不總是表示工作日的數量。這就是大多數數據庫必須使用日曆表的原因。他們不佔用大量內存並簡化了大量查詢。

但是,如果這是不是一種選擇,那麼你可以在飛行中相對容易地生成日期的表,如果你需要計算使用該

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; 

Example on SQL-Fiddle

+0

請參閱http://img707.imageshack.us/img707/1346/luyk.jpg但是string_val不包括日期 – user2943856

+0

String_Val計算'@ d1'和'@ d2'之間的日期,但不包括日期之間你的表格(date1和date2),這就是爲什麼你得到的所有行重複相同的數字。 – GarethD

+0

@GerethD完美!非常感謝你! – user2943856

2

這並不排除它的日子了,但日期部分,而不是描述。您可以將用作參數的參數替換爲查詢中的值。

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)[email protected]@datefirst when 8 then 1 else 0 end) 
    -(case datepart(dw, @EndDate)[email protected]@datefirst when 7 then 1 when 14 then 1 else 0 end) 

Returns 7 
0

爲了增加GarethD的答案 - 我放在一起SQL日曆表的美國版本,設置爲is_working_day =假所有節假日和週六日......對於任何人想的SQL,在這裏是:

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 
相關問題