按某个“开始日期”

时间:2016-05-23 10:59:12

标签: sql-server-2008 tsql

我有两张桌子,一张项目表和一张日历表。第一个包含一个开始日期和所需的日期。日历表包含通常的日期信息,例如日期,dayofweek,以及列是工作日,显示该日是星期六,星期日或银行假日(值= 0)还是常规工作日(值= 1)。 / p>

对于某个报告,我需要编写一个存储过程,通过添加所需的估计工作日数来计算预测的最终日期。

示例:

**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(这导致预测的结束日期为10.05.2016)。是否可以以某种方式加入表格,这样我就可以添加类似

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

我会发布一些更多的代码,但我完全不知道从哪里开始。

谢谢!

4 个答案:

答案 0 :(得分: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;

这不是问题的一部分,但是对于将来的验证,使用OFFSET/FETCH

在SQL Server 2012+中更容易实现
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因为您希望结束日期包括范围)来查找项目指定的前几天数

如果你计划在非工作日开始你的项目,这将失败,所以一个更强大的解决方案可能是:

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在项目开始日期或之后获得下一个工作日,然后应用与之前相同的连接。

答案 1 :(得分:1)

此查询返回一个表,其中包含每个项目的预测enddate

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

答案 2 :(得分: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

答案 3 :(得分:0)

使用以下逻辑

"DATE","TIME","IP","LOOKING_FOR"
"2016-05-22","07:30:40","XX.XX.XX.XX","/site.php?=dTM_c1_uid7"
"2016-05-22","07:31:10","XX.XX.XX.XX","/site.php?=dTM_c1_uid7"
"2016-05-22","07:31:19","XX.XX.XX.XX","/site.php?=dTM_c1_uid8"