2016-05-23 149 views
3

我有兩個表格,一個項目表格和一個日曆表格。第一個包含startdate和days所需的時間。日曆表包含常用的日期信息,如日期,星期幾,以及列是工作日,表示日期是星期六,星期日還是銀行假期(值= 0)或正常工作日(值= 1)。從某個開始日期開始計算工作天數

對於某個報告,我需要編寫一個存儲過程,通過添加所需的預計工作日數來計算預測結束日期。

實施例:

**Projects** 
Name   Start_Planned Work_days_Required 
Project A 02.05.2016  6 

Calendar (04.05 is a bank holdiday) 
Day   Weekday  Workingday 
01.05.2016 7    0 
02.05.2016 1    1  
03.05.2016 2    1 
04.05.2016 3    0 
05.05.2016 4    1 
06.05.2016 5    1 
07.05.2016 6    0 
08.05.2016 7    0 
09.05.2016 1    1 
10.05.2016 2    1 

比方說,估計的數目給定爲6(這會導致2016年5月10日的預測結束日期)所需的天。是否有可能加盟的方式,這讓我把東西像

select date as enddate_predicted 
from calendar 
join projects 
where number_of_days = 6 

我會發布更多的代碼表,但我很卡如何從哪裏開始。

謝謝!

+0

不Projects.Start_Planned具有1:1的與Calendar.Day關係?平日專欄是必要的嗎? – qxg

回答

1

你可以得到所有工作日第一次約會後,再申請ROW_NUMBER()得到的天數爲每個日期:

SELECT Date, DayNum = ROW_NUMBER() OVER(ORDER BY Date) 
FROM Calendar 
WHERE IsWorkingDay = 1 
AND  Date >= @StartPlanned 

然後,它也只是對第6天過濾的情況下:

DECLARE @StartPlanned DATE = '20160502', 
     @Days INT = 6; 

SELECT Date 
FROM ( SELECT Date, DayNum = ROW_NUMBER() OVER(ORDER BY Date) 
      FROM Calendar 
      WHERE WorkingDay = 1 
      AND  Date >= @StartPlanned 
     ) AS c 
WHERE c.DayNum = @Days; 

這不是問題的一部分,但對於未來的打樣,這是更容易在SQL Server 2012+到acheive與OFFSET/FETCH

DECLARE @StartPlanned DATE = '20160502', 
     @Days INT = 6; 

SELECT Date 
FROM dbo.Calendar 
WHERE Date >= @StartPlanned 
AND  WorkingDay = 1 
ORDER BY Date 
OFFSET (@Days - 1) ROWS FETCH NEXT 1 ROWS ONLY 

附錄

我錯過了早前部分關於有另一個表中,關於把它變成一個遊標的評論促使我修改我的答案。我想補充一個新的列到你叫WorkingDayRank年曆表:

ALTER TABLE dbo.Calendar ADD WorkingDayRank INT NULL; 
GO 
UPDATE c 
SET  WorkingDayRank = wdr 
FROM ( SELECT Date, wdr = ROW_NUMBER() OVER(ORDER BY Date) 
      FROM dbo.Calendar 
      WHERE WorkingDay = 1 
     ) AS c; 

這可以即時完成,但它存儲爲一個值,你會得到更好的性能,那麼您的查詢就會變成:

SELECT p.Name, 
     p.Start_Planned, 
     p.Work_days_Required, 
     EndDate = c2.Date 
FROM Projects AS P 
     INNER JOIN dbo.Calendar AS c1 
      ON c1.Date = p.Start_Planned 
     INNER JOIN dbo.Calendar AS c2 
      ON c2.WorkingDayRank = c1.WorkingDayRank + p.Work_days_Required - 1; 

這只是獲取你的起始日期的工作日排名,並找到未來該項目通過連接在WorkingDayRank指定的天數(-1,因爲你想要的結束日期以下的範圍內的)

這將失敗,如果你e版本計劃雖然開始在非工作日項目,讓一個更強大的解決方案可能是:

SELECT p.Name, 
     p.Start_Planned, 
     p.Work_days_Required, 
     EndDate = c2.Date 
FROM Projects AS P 
     CROSS APPLY 
     ( SELECT TOP 1 c1.Date, c1.WorkingDayRank 
      FROM dbo.Calendar AS c1 
      WHERE c1.Date >= p.Start_Planned 
      AND  c1.WorkingDay = 1 
      ORDER BY c1.Date 
     ) AS c1 
     INNER JOIN dbo.Calendar AS c2 
      ON c2.WorkingDayRank = c1.WorkingDayRank + p.Work_days_Required - 1; 

這使用CROSS APPLY得到或您的項目開始日期後的下一個工作日,則適用相同的連接像之前一樣。

+0

把它放在遊標中也可以。謝謝 –

0

- 這給了我所有的項目信息

select p.projectname,p.Start_Planned ,c.date, 
    from calendar c 
    join 
    projects o 
    on c.date=dateadd(days,p.Work_days_Required,p.Start_Planned) 
    and c.isworkingday=1 

現在你可以使用CTE像下面或在程序

;with cte 
as 
(
    Select 
     p.projectnam 
     p.Start_Planned , 
     c.date,datediff(days,p.Start_Planned,c.date) as nooffdays 
     from calendar c 
     join 
     projects o 
     on c.date=dateadd(days,p.Work_days_Required,p.Start_Planned) 
     and c.isworkingday=1 
) 
select * from cte where nooffdays=6 
1

該查詢這個包裹爲每個項目返回一個包含預測結束日期的表格

select name,min(day) as predicted_enddate from (
    select c.day,p.name from dbo.Calendar c 
    join dbo.Calendar c2 on c.day>=c2.day 
    join dbo.Projects p on p.start_planned<=c.day and p.start_planned<=c2.day 
    group by c.day,p.work_days_required,p.name 
    having sum(c2.workingday)=p.work_days_required 
) a 
group by name 
+0

工作正常!謝謝! –

0

使用以下邏輯

CREATE TABLE #proj(Name varchar(50),Start_Planned date, 

Work_days_Required int) 

insert into #proj 
values('Project A','02.05.2016',6) 

CReATE TABLE #Calendar(Day date,Weekday int,Workingday bit) 

insert into #Calendar 
values('01.05.2016',7,0), 
('02.05.2016',1,1), 
('03.05.2016',2,1), 
('04.05.2016',3,0), 
('05.05.2016',4,1), 
('06.05.2016',5,1), 
('07.05.2016',6,0), 
('08.05.2016',7,0), 
('09.05.2016',1,1), 
('10.05.2016',2,1) 


DECLARE @req_day int = 3 
DECLARE @date date = '02.05.2016' 

--SELECT @req_day = Work_days_Required FROM #proj where Start_Planned = @date 

select *,row_number() over(order by [day] desc) as cnt 
    from #Calendar 
    where Workingday = 1 
     and [Day] > @date 

SELECT * 
FROM 
(
    select *,row_number() over(order by [day] desc) as cnt 
    from #Calendar 
    where Workingday = 1 
     and [Day] > @date 
)a 
where cnt = @req_day 
相關問題